diff --git a/deps/db/src/logseq/db.cljs b/deps/db/src/logseq/db.cljs index 3e94c5943..5a7cbc888 100644 --- a/deps/db/src/logseq/db.cljs +++ b/deps/db/src/logseq/db.cljs @@ -524,7 +524,7 @@ :block/parent [:block/uuid page-id] :block/order (db-order/gen-key nil) :block/page [:block/uuid page-id] - :logseq.property/view-for :all-pages})]))) + :logseq.property/view-for [:block/uuid page-id]})]))) ;; TODO: why not generate a UUID for all local graphs? ;; And prefer this local graph UUID when picking an ID for new rtc graph? @@ -588,8 +588,7 @@ [db] (when (db-based-graph? db) (when-let [page (get-page db common-config/views-page-name)] - (->> (:block/_parent page) - (filter (fn [b] (= :all-pages (:logseq.property/view-for b)))))))) + (:logseq.property/_view-for page)))) (defn inline-tag? [block-raw-title tag] diff --git a/deps/db/src/logseq/db/frontend/property.cljs b/deps/db/src/logseq/db/frontend/property.cljs index 65be173d1..0fc5df518 100644 --- a/deps/db/src/logseq/db/frontend/property.cljs +++ b/deps/db/src/logseq/db/frontend/property.cljs @@ -219,7 +219,7 @@ :hide? true :public? false}} :logseq.property/view-for {:schema - {:type :keyword + {:type :node :hide? true :public? false}} :logseq.property.asset/remote-metadata {:schema diff --git a/deps/db/src/logseq/db/frontend/schema.cljs b/deps/db/src/logseq/db/frontend/schema.cljs index 35914168e..ef73de452 100644 --- a/deps/db/src/logseq/db/frontend/schema.cljs +++ b/deps/db/src/logseq/db/frontend/schema.cljs @@ -2,7 +2,7 @@ "Main datascript schemas for the Logseq app" (:require [clojure.set :as set])) -(def version 19) +(def version 20) ;; A page is a special block, a page can corresponds to multiple files with the same ":block/name". (def ^:large-vars/data-var schema {:db/ident {:db/unique :db.unique/identity} diff --git a/src/main/frontend/components/objects.cljs b/src/main/frontend/components/objects.cljs index b86469b31..1972abf92 100644 --- a/src/main/frontend/components/objects.cljs +++ b/src/main/frontend/components/objects.cljs @@ -14,7 +14,11 @@ [rum.core :as rum] [frontend.modules.outliner.ui :as ui-outliner-tx] [frontend.modules.outliner.op :as outliner-op] - [frontend.db.react :as react])) + [frontend.db.react :as react] + [logseq.shui.ui :as shui] + [frontend.util :as util] + [frontend.ui :as ui] + [logseq.common.config :as common-config])) (defn- get-class-objects [class] @@ -33,15 +37,72 @@ (defn- get-views [ent] (let [class (db/entity (:db/id ent))] - (-> (filter (fn [b] - (= (:db/ident class) (:logseq.property/view-for b))) - (:block/_parent class)) - (ldb/sort-by-order)))) + (-> (:logseq.property/_view-for class) + (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)))} + (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" {}))]) (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) columns (views/build-columns config properties)] @@ -55,7 +116,10 @@ (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/persist-state filters)] (set-filters! filters) - (p/let [entity (or entity (create-view!))] - (property-handler/set-block-property! repo (:db/id entity) :logseq.property.table/filters filters)))) + (property-handler/set-block-property! repo (:db/id entity) :logseq.property.table/filters filters))) :set-visible-columns! (fn [columns] (let [hidden-columns (vec (keep (fn [[column visible?]] (when (false? visible?) column)) columns))] (set-visible-columns! columns) - (p/let [entity (or entity (create-view!))] - (property-handler/set-block-property! repo (:db/id entity) :logseq.property.table/hidden-columns hidden-columns)))) + (property-handler/set-block-property! repo (:db/id entity) :logseq.property.table/hidden-columns hidden-columns))) :set-ordered-columns! (fn [ordered-columns] (let [ids (vec (remove #{:select} ordered-columns))] (set-ordered-columns! ordered-columns) - (p/let [entity (or entity (create-view!))] - (property-handler/set-block-property! repo (:db/id entity) :logseq.property.table/ordered-columns ids))))})) + (property-handler/set-block-property! repo (:db/id entity) :logseq.property.table/ordered-columns ids)))})) (rum/defc table-view < rum/static [table option row-selection add-new-object! ready?] @@ -963,7 +958,7 @@ :ref? true))))) (rum/defc view-inner < rum/static - [view-entity {:keys [data set-data! columns add-new-object! create-view! title-key render-empty-title?] :as option + [view-entity {:keys [data set-data! columns add-new-object! views-title title-key render-empty-title?] :as option :or {render-empty-title? false}}] (let [[input set-input!] (rum/use-state "") sorting (:logseq.property.table/sorting view-entity) @@ -978,8 +973,7 @@ (db-set-table-state! view-entity {:set-sorting! set-sorting! :set-filters! set-filters! :set-visible-columns! set-visible-columns! - :set-ordered-columns! set-ordered-columns! - :create-view! create-view!}) + :set-ordered-columns! set-ordered-columns!}) row-filter-fn (fn [] (fn [row] (row-matched? row input filters))) @@ -1020,9 +1014,11 @@ [:div.flex.flex-wrap.items-center.justify-between.gap-1 (when-not render-empty-title? [:div.flex.flex-row.items-center.gap-2 - [:div.font-medium.opacity-50.text-sm - (t (or title-key :views.table/default-title) - (count (:rows table)))]]) + (or + views-title + [:div.font-medium.opacity-50.text-sm + (t (or title-key :views.table/default-title) + (count (:rows table)))])]) [:div.view-actions.flex.items-center.gap-1 (filter-properties columns table) @@ -1057,4 +1053,5 @@ (rum/defc view < rum/reactive [view-entity option] (let [view-entity' (db/sub-block (:db/id view-entity))] - (view-inner view-entity' option))) + (rum/with-key (view-inner view-entity' option) + (str "view-" (:db/id view-entity'))))) diff --git a/src/main/frontend/db/async.cljs b/src/main/frontend/db/async.cljs index 628f1872a..18713862e 100644 --- a/src/main/frontend/db/async.cljs +++ b/src/main/frontend/db/async.cljs @@ -280,8 +280,7 @@ '[:find [(pull ?b [*]) ...] :in $ ?class-id :where - [?class-id :db/ident ?ident] - [?b :logseq.property/view-for ?ident]] + [?b :logseq.property/view-for ?class-id]] class-id)) (defn > (.exec sqlite-db #js {:sql "SELECT NAME FROM PRAGMA_TABLE_INFO('kvs')" @@ -230,7 +249,8 @@ [16 {:properties [:logseq.property.class/hide-from-node]}] [17 {:fix update-db-attrs-type}] [18 {:properties [:logseq.property.view/type]}] - [19 {:classes [:logseq.class/Query]}]]) + [19 {:classes [:logseq.class/Query]}] + [20 {:fix fix-view-for}]]) (let [max-schema-version (apply max (map first schema-version->updates))] (assert (<= db-schema/version max-schema-version))