Browse Source

Merge branch 'feat/db' into chore/whiteboards-cleanup

Konstantinos Kaloutas 1 year ago
parent
commit
05aac2ec10

+ 3 - 10
src/main/frontend/components/container.cljs

@@ -104,7 +104,7 @@
           {:class "w-60"}
           (when-not recent?
             (shui/context-menu-item
-              {:on-click #(page-handler/unfavorite-page! original-name)}
+              {:on-click #(page-handler/<unfavorite-page! original-name)}
               (ctx-icon "star-off")
               (t :page/unfavorite)
               (shui/context-menu-shortcut (some-> (shortcut-dh/shortcut-binding :command/toggle-favorite) (first)
@@ -132,14 +132,7 @@
 
 (rum/defc favorites < rum/reactive
   [t]
-  (let [favorites (->> (:favorites (state/sub-config))
-                       (remove string/blank?)
-                       (filter string?)
-                       (mapv util/safe-page-name-sanity-lc)
-                       (distinct))
-        favorite-entities (->> favorites
-                               (mapv #(db/entity [:block/name %]))
-                               (remove nil?))]
+  (let [favorite-entities (page-handler/get-favorites)]
     (nav-content-item
      [:a.flex.items-center.text-sm.font-medium.rounded-md.wrap-th
       (ui/icon "star" {:size 16})
@@ -162,7 +155,7 @@
                         favorite-entities)]
          (dnd-component/items favorites
                               {:on-drag-end (fn [favorites]
-                                              (page-handler/reorder-favorites! favorites))
+                                              (page-handler/<reorder-favorites! favorites))
                                :parent-node :ul.favorites.text-sm}))))))
 
 (rum/defc recent-pages < rum/reactive db-mixins/query

+ 1 - 1
src/main/frontend/components/db_based/page.cljs

@@ -170,7 +170,7 @@
             true)
       [:div.page-info {:on-mouse-over #(reset! *hover? true)
                        :on-mouse-leave #(reset! *hover? false)}
-       (when (or hover-or-expanded? has-tags? has-properties?)
+       (when (or hover-or-expanded? has-tags? has-properties? class?)
          [:div.fade-in.p-2 {:class (if (or @*hover? (not collapsed?))
                                      "border rounded"
                                      "border rounded border-transparent")}

+ 3 - 5
src/main/frontend/components/page_menu.cljs

@@ -71,9 +71,7 @@
           contents? (= page-name "contents")
           properties (:block/properties page)
           public? (true? (pu/lookup properties :public))
-          favorites (:favorites (state/sub-config))
-          favorited? (contains? (set (map util/page-name-sanity-lc favorites))
-                                page-name)
+          favorited? (page-handler/favorited? page-name)
           developer-mode? (state/sub [:ui/developer-mode?])
           file-rpath (when (util/electron?) (page-util/get-page-file-rpath page-name))
           _ (state/sub :auth/id-token)
@@ -91,8 +89,8 @@
              :options {:on-click
                        (fn []
                          (if favorited?
-                           (page-handler/unfavorite-page! page-original-name)
-                           (page-handler/favorite-page! page-original-name)))}})
+                           (page-handler/<unfavorite-page! page-original-name)
+                           (page-handler/<favorite-page! page-original-name)))}})
 
           (when (or (util/electron?) file-sync-graph-uuid)
             {:title   (t :page/version-history)

+ 69 - 95
src/main/frontend/components/property.cljs

@@ -15,7 +15,6 @@
             [frontend.handler.page :as page-handler]
             [frontend.handler.property.util :as pu]
             [frontend.handler.db-based.property.util :as db-pu]
-            [frontend.mixins :as mixins]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.search :as search]
             [frontend.state :as state]
@@ -27,7 +26,6 @@
             [frontend.handler.route :as route-handler]
             [frontend.components.icon :as icon-component]
             [frontend.components.dnd :as dnd]
-            [dommy.core :as dom]
             [frontend.components.property.closed-value :as closed-value]
             [frontend.components.property.util :as components-pu]
             [promesa.core :as p]))
@@ -329,8 +327,7 @@
 (defn- add-property-from-dropdown
   "Adds an existing or new property from dropdown. Used from a block or page context.
    For pages, used to add both schema properties or properties for a page"
-  [entity property-name {:keys [class-schema? page-configure?
-                                *show-new-property-config?]}]
+  [entity property-name {:keys [class-schema? page-configure?]}]
   (let [repo (state/get-current-repo)]
     ;; existing property selected or entered
     (if-let [_property (get-property-from-db property-name)]
@@ -347,10 +344,9 @@
       (if (db-property/valid-property-name? property-name)
         (if (and (contains? (:block/type entity) "class") page-configure?)
           (pv/<add-property! entity property-name "" {:class-schema? class-schema? :exit-edit? page-configure?})
-          (do
+          (p/do!
             (db-property-handler/upsert-property! repo property-name {} {})
-            (when *show-new-property-config?
-              (reset! *show-new-property-config? true))))
+            true))
         (do (notification/show! "This is an invalid property name. A property name cannot start with page reference characters '#' or '[['." :error)
             (pv/exit-edit-property))))))
 
@@ -398,35 +394,39 @@
     [:div.ls-property-input.flex.flex-1.flex-row.items-center.flex-wrap.gap-1
      (if in-block-container? {:style {:padding-left 22}} {})
      (if @*property-key
-       (when-let [property (get-property-from-db @*property-key)]
+       (let [property (get-property-from-db @*property-key)]
          [:div.ls-property-add.grid.grid-cols-5.gap-1.flex.flex-1.flex-row.items-center
           [:div.flex.flex-row.items-center.col-span-2
            [:span.bullet-container.cursor [:span.bullet]]
            [:div {:style {:padding-left 6}} @*property-key]]
-          [:div.col-span-3.flex.flex-row {:on-mouse-down (fn [e] (util/stop-propagation e))}
-           (when-not class-schema?
-             (if @*show-new-property-config?
-               (ui/dropdown
-                (fn [_opts]
-                  (pv/property-value entity property @*property-value
-                                     (assoc opts
-                                            :editing? true
-                                            :*show-new-property-config? *show-new-property-config?)))
-                (fn [{:keys [toggle-fn]}]
-                  [:div.p-6
-                   (property-config entity property (merge opts {:toggle-fn toggle-fn
-                                                                 :block entity
-                                                                 :add-new-property? true
-                                                                 :*show-new-property-config? *show-new-property-config?}))])
-                {:initial-open? true
-                 :modal-class (util/hiccup->class
-                               "origin-top-right.absolute.left-0.rounded-md.shadow-lg.mt-2")})
-               (pv/property-value entity property @*property-value (assoc opts :editing? true))))]])
+          (when property
+            [:div.col-span-3.flex.flex-row {:on-mouse-down (fn [e] (util/stop-propagation e))}
+             (when-not class-schema?
+               (if @*show-new-property-config?
+                 (ui/dropdown
+                  (fn [_opts]
+                    (pv/property-value entity property @*property-value
+                                       (assoc opts
+                                              :editing? true
+                                              :*show-new-property-config? *show-new-property-config?)))
+                  (fn [{:keys [toggle-fn]}]
+                    [:div.p-6
+                     (property-config entity property (merge opts {:toggle-fn toggle-fn
+                                                                   :block entity
+                                                                   :add-new-property? true
+                                                                   :*show-new-property-config? *show-new-property-config?}))])
+                  {:initial-open? true
+                   :modal-class (util/hiccup->class
+                                 "origin-top-right.absolute.left-0.rounded-md.shadow-lg.mt-2")})
+                 (pv/property-value entity property @*property-value (assoc opts :editing? true))))])])
 
        (let [on-chosen (fn [{:keys [value]}]
                          (reset! *property-key value)
-                         (add-property-from-dropdown entity value (assoc opts :*show-new-property-config? *show-new-property-config?)))
-             input-opts {:on-blur (fn [] (pv/exit-edit-property))
+                         (p/let [result (add-property-from-dropdown entity value opts)]
+                           (when (and (true? result) *show-new-property-config?)
+                             (reset! *show-new-property-config? true))))
+             input-opts {:on-blur (fn []
+                                    (pv/exit-edit-property))
                          :on-key-down
                          (fn [e]
                            (case (util/ekey e)
@@ -435,66 +435,38 @@
                              nil))}]
          (property-select exclude-properties on-chosen input-opts)))]))
 
-(defonce *last-new-property-input-id (atom nil))
-(rum/defcs new-property < rum/reactive
+(rum/defcs new-property < rum/reactive rum/static
+  (rum/local false ::new-property?)
   (rum/local nil ::property-key)
   (rum/local nil ::property-value)
-  (rum/local false ::enter-key-down-triggered?)
-  (mixins/event-mixin
-   (fn [state]
-     (mixins/hide-when-esc-or-outside
-      state
-      :on-hide (fn []
-                 (when-not (:editor/property-configure? @state/state)
-                   (property-handler/set-editing-new-property! nil)))
-      :node (js/document.getElementById "edit-new-property"))
-     (mixins/on-key-down state
-                         ;; enter
-                         {13 (fn [_e]
-                               (reset! *last-new-property-input-id (:ui/new-property-input-id @state/state))
-                               (reset! (::enter-key-down-triggered? state) true))})
-     (mixins/on-enter state
-                      {:on-enter (fn [e]
-                                   (when-not (or (state/editing?)
-                                                 (state/selection?))
-                                     (when (and
-                                            @(::enter-key-down-triggered? state)
-                                            (or (= "main-content-container" (.-id (.-target e)))
-                                                (= (.-tagName (.-target e)) "BODY")))
-                                       (let [nodes (dom/by-class "add-property")
-                                             last-input-id @*last-new-property-input-id
-                                             node (if last-input-id
-                                                    (some (fn [node]
-                                                            (when (dom/has-class? node last-input-id) node)) nodes)
-                                                    (first nodes))]
-                                         (when node (.click node)))
-                                       (reset! (::enter-key-down-triggered? state) false))))
-                       :node js/window})))
-  [state block edit-input-id new-property? opts]
-  [:div.ls-new-property
-   (let [*property-key (::property-key state)
-         *property-value (::property-value state)]
-     (cond
-       new-property?
-       [:div#edit-new-property
-        (property-input block *property-key *property-value opts)]
-
-       (and (or (db-property-handler/block-has-viewable-properties? block)
-                (:page-configure? opts))
-            (not config/publishing?)
-            (not (:in-block-container? opts)))
-       [:a.fade-link.flex.add-property
-        {:class edit-input-id
-         :on-click (fn []
-                     (property-handler/set-editing-new-property! edit-input-id)
-                     (reset! *property-key nil)
-                     (reset! *property-value nil))}
-        [:div.flex.flex-row.items-center {:style {:padding-left 1}}
-         (ui/icon "plus" {:size 15})
-         [:div.ml-1.text-sm {:style {:padding-left 2}} "Add property"]]]
-
-       :else
-       [:div {:style {:height 28}}]))])
+  [state block id opts]
+  (let [*new-property? (::new-property? state)
+        container-id (state/sub :editor/properties-container)
+        new-property? (and @*new-property? (= container-id id))]
+    [:div.ls-new-property
+     (let [*property-key (::property-key state)
+           *property-value (::property-value state)]
+       (cond
+         new-property?
+         (property-input block *property-key *property-value opts)
+
+         (and (or (db-property-handler/block-has-viewable-properties? block)
+                  (:page-configure? opts))
+              (not config/publishing?)
+              (not (:in-block-container? opts)))
+         [:a.fade-link.flex.add-property
+          {:on-click (fn []
+                       (state/set-state! :editor/block block)
+                       (state/set-state! :editor/properties-container id)
+                       (reset! *new-property? true)
+                       (reset! *property-key nil)
+                       (reset! *property-value nil))}
+          [:div.flex.flex-row.items-center {:style {:padding-left 1}}
+           (ui/icon "plus" {:size 15})
+           [:div.ml-1.text-sm {:style {:padding-left 2}} "Add property"]]]
+
+         :else
+         [:div {:style {:height 28}}]))]))
 
 (defn- property-collapsed?
   [block property]
@@ -652,8 +624,11 @@
 
 ;; TODO: Remove :page-configure? as it only ever seems to be set to true
 (rum/defcs ^:large-vars/cleanup-todo properties-area < rum/reactive
-  [state target-block edit-input-id {:keys [in-block-container? page-configure? class-schema?] :as opts}]
-  (let [block (resolve-linked-block-if-exists target-block)
+  {:init (fn [state]
+           (assoc state ::id (str (random-uuid))))}
+  [state target-block _edit-input-id {:keys [in-block-container? page-configure? class-schema?] :as opts}]
+  (let [id (::id state)
+        block (resolve-linked-block-if-exists target-block)
         block-properties (:block/properties block)
         properties (if (and class-schema? page-configure?)
                      (let [properties (:properties (:block/schema block))]
@@ -703,7 +678,6 @@
                           (concat block-own-properties' class-own-properties)
                           block-own-properties'))
         full-hidden-properties (concat block-hidden-properties class-hidden-properties)
-        new-property? (= edit-input-id (state/sub :ui/new-property-input-id))
         class->properties (loop [classes all-classes
                                  properties #{}
                                  result []]
@@ -717,11 +691,11 @@
                               result))]
     (when-not (and (empty? block-own-properties)
                    (empty? class->properties)
-                   (not new-property?)
                    (not (:page-configure? opts)))
       [:div.ls-properties-area (cond-> (if in-block-container?
-                                         {}
-                                         {:class (when class-schema?  "class-properties")})
+                                         {:id id}
+                                         {:id id
+                                          :class (when class-schema?  "class-properties")})
                                  (:selected? opts)
                                  (update :class conj "select-none"))
        (properties-section block (if class-schema? properties own-properties) opts)
@@ -729,8 +703,8 @@
        (when (and (seq full-hidden-properties) (not class-schema?) (not config/publishing?))
          (hidden-properties block full-hidden-properties opts))
 
-       (when (or new-property? (not in-block-container?))
-         (new-property block edit-input-id new-property? opts))
+       (when (not in-block-container?)
+         (rum/with-key (new-property block id opts) (str id "-add-property")))
 
        (when (and (seq class->properties) (not one-class?))
          (let [page-cp (:page-cp opts)]

+ 10 - 9
src/main/frontend/components/property/value.cljs

@@ -34,7 +34,6 @@
   ([property-configure-check?]
    (when (or (and property-configure-check? (not (:editor/property-configure? @state/state)))
              (not property-configure-check?))
-     (property-handler/set-editing-new-property! nil)
      (state/clear-edit!))))
 
 (defn set-editing!
@@ -312,12 +311,14 @@
 
 (defn <create-new-block!
   [block property value]
-  (p/let [last-block-id (db-property-handler/create-property-text-block! block property value
-                                                                       editor-handler/wrap-parse-block
+  (let [{:keys [last-block-id result]} (db-property-handler/create-property-text-block! block property value
+                                                                                        editor-handler/wrap-parse-block
 
-                                                                       {})
-          _ (exit-edit-property)]
-    (editor-handler/edit-block! (db/entity [:block/uuid last-block-id]) :max last-block-id)))
+                                                                                        {})]
+    (p/do!
+     result
+     (exit-edit-property)
+     (editor-handler/edit-block! (db/entity [:block/uuid last-block-id]) :max last-block-id))))
 
 (defn <create-new-block-from-template!
   "`template`: tag block"
@@ -342,14 +343,14 @@
            esc? (= (util/ekey e) "Escape")
            backspace? (= (util/ekey e) "Backspace")
            new-value (util/evalue e)
-           new-property? (some? (:ui/new-property-input-id @state/state))]
+           new-property? (:editor/properties-container @state/state)]
        (when (and (or enter? esc? backspace?)
                   (not (state/get-editor-action)))
          (when-not backspace? (util/stop e))
          (cond
            (or esc?
-               (and enter? new-property?)
-               (and enter? (util/tag? new-value)))
+               (and enter? (util/tag? new-value))
+               (and enter? new-property?))
            (save-text! repo block property value editor-id e)
 
            enter?

+ 5 - 1
src/main/frontend/db_worker.cljs

@@ -405,7 +405,11 @@
 
   (file-writes-finished?
    [this]
-   (empty? @file/*writes))
+   (if (empty? @file/*writes)
+     true
+     (do
+       (js/console.log "Unfinished file writes:" @file/*writes)
+       false)))
 
   (page-file-saved
    [this request-id page-id]

+ 63 - 3
src/main/frontend/handler/common/page.cljs

@@ -15,7 +15,21 @@
             [frontend.fs :as fs]
             [promesa.core :as p]
             [frontend.handler.block :as block-handler]
-            [frontend.handler.file-based.recent :as file-recent-handler]))
+            [frontend.handler.file-based.recent :as file-recent-handler]
+            [frontend.format.block :as block]
+            [logseq.db :as ldb]
+            [frontend.db.conn :as conn]
+            [datascript.core :as d]
+            [frontend.handler.editor :as editor-handler]
+            [frontend.modules.outliner.ui :as ui-outliner-tx]
+            [logseq.outliner.core :as outliner-core]))
+
+(defn build-hidden-page-tx-data
+  [page-name]
+  (let [page-name* (str "$$$" page-name)]
+    (assoc (block/page-name->map page-name* false false)
+           :block/type #{"hidden"}
+           :block/format :markdown)))
 
 ;; TODO: return page entity instead
 (defn create!
@@ -94,6 +108,47 @@
       (when-not (= old-favorites new-favorites)
         (config-handler/set-config! :favorites new-favorites)))))
 
+(def favorites-page-name "$$$favorites")
+
+(defn- find-block-in-favorites-page
+  [page-block-uuid]
+  (let [db (conn/get-db)
+        page-block-uuid-str (str page-block-uuid)
+        blocks (ldb/get-page-blocks db favorites-page-name {})]
+    (some (fn [block]
+            (when (= page-block-uuid-str (:block/content block))
+              block))
+          blocks)))
+
+(defn favorited?-v2
+  [page-block-uuid]
+  {:pre [(uuid? page-block-uuid)]}
+  (some? (find-block-in-favorites-page page-block-uuid)))
+
+(defn <favorite-page!-v2
+  [page-block-uuid]
+  {:pre [(uuid? page-block-uuid)]}
+  (let [favorites-page (d/entity (conn/get-db) [:block/name favorites-page-name])
+        favorites-page-tx-data (build-hidden-page-tx-data "favorites")]
+    (p/do!
+     (when-not favorites-page (ldb/transact! nil [favorites-page-tx-data]))
+     (editor-handler/api-insert-new-block!
+      (str page-block-uuid)
+      {:page favorites-page-name :edit-block? false}))))
+
+(defn <unfavorite-page!-v2
+  [page-block-uuid]
+  {:pre [(uuid? page-block-uuid)]}
+  (let [repo (state/get-current-repo)]
+    (when-let [block (find-block-in-favorites-page page-block-uuid)]
+      (ui-outliner-tx/transact!
+       {:outliner-op :delete-blocks}
+       (outliner-core/delete-blocks! repo (conn/get-db false) (state/get-date-formatter) [block] {})))))
+
+
+;; favorites fns end ================
+
+
 (defn delete!
   "Deletes a page and then either calls the ok-handler or the error-handler if unable to delete"
   [page-name ok-handler & {:keys [_persist-op? _error-handler]
@@ -111,7 +166,12 @@
   [repo page-name file-path tx-meta]
   (let [repo-dir (config/get-repo-dir repo)]
       ;; TODO: move favorite && unfavorite to worker too
-    (unfavorite-page! page-name)
+    (if (config/db-based-graph? repo)
+      (when-let [page-block-uuid (:block/uuid
+                                  (d/entity (conn/get-db repo)
+                                            [:block/name (common-util/page-name-sanity-lc page-name)]))]
+        (<unfavorite-page!-v2 page-block-uuid))
+      (unfavorite-page! page-name))
 
     (when (and (not= :rename-page (:real-outliner-op tx-meta))
                (= (some-> (state/get-current-page) common-util/page-name-sanity-lc)
@@ -154,7 +214,7 @@
                                 :push        false
                                 :path-params {:name new-page-name}}))
 
-    (when (favorited? old-page-name)
+    (when (and (config/db-based-graph? repo) (favorited? old-page-name))
       (unfavorite-page! old-page-name)
       (favorite-page! new-page-name))
     (let [home (get (state/get-config) :default-home {})]

+ 8 - 8
src/main/frontend/handler/db_based/property.cljs

@@ -99,13 +99,12 @@
   (let [property (db/entity [:block/name (common-util/page-name-sanity-lc k-name)])
         k-name (name k-name)
         property-uuid (or (:block/uuid property) property-uuid (db/new-block-id))]
-    (when property
+    (if property
       (db/transact! repo [(outliner-core/block-with-updated-at
                            {:block/schema schema
                             :block/uuid property-uuid
                             :block/type "property"})]
-                    {:outliner-op :save-block}))
-    (when (nil? property) ;if property not exists yet
+                    {:outliner-op :save-block})
       (db/transact! repo [(sqlite-util/build-new-property
                            (cond-> {:block/original-name k-name
                                     :block/name (util/page-name-sanity-lc k-name)
@@ -618,11 +617,12 @@
         class? (contains? (:block/type block) "class")
         property-key (:block/original-name property)]
     (db/transact! repo (if page (cons page blocks) blocks) {:outliner-op :insert-blocks})
-    (when property-key
-      (if (and class? class-schema?)
-        (class-add-property! repo (:block/uuid block) property-key)
-        (set-block-property! repo (:block/uuid block) property-key (:block/uuid first-block) {})))
-    last-block-id))
+    (let [result (when property-key
+                   (if (and class? class-schema?)
+                     (class-add-property! repo (:block/uuid block) property-key)
+                     (set-block-property! repo (:block/uuid block) property-key (:block/uuid first-block) {})))]
+      {:last-block-id last-block-id
+       :result result})))
 
 (defn property-create-new-block-from-template
   [block property template]

+ 15 - 13
src/main/frontend/handler/editor.cljs

@@ -3448,19 +3448,21 @@
    (when block-id
      (let [repo (state/get-current-repo)]
        (if-let [block (db/entity [:block/uuid block-id])]
-         (or (db-model/has-children? block-id)
-             (valid-dsl-query-block? block)
-             (valid-custom-query-block? block)
-             (and (config/db-based-graph? repo)
-                  (seq (:block/properties block))
-                  (not (db-pu/all-hidden-built-in-properties? (keys (:block/properties block)))))
-             (and (config/db-based-graph? repo)
-                  (seq (:block/tags block)))
-             (and
-              (:outliner/block-title-collapse-enabled? (state/get-config))
-              (block-with-title? (:block/format block)
-                                 (:block/content block)
-                                 semantic?)))
+         (let [db-based? (config/db-based-graph? repo)
+               tags (:block/tags (db/entity (:db/id block)))]
+           (or (db-model/has-children? block-id)
+               (valid-dsl-query-block? block)
+               (valid-custom-query-block? block)
+               (and db-based?
+                    (seq (:block/properties block))
+                    (not (db-pu/all-hidden-built-in-properties? (keys (:block/properties block)))))
+               (and db-based? (seq tags)
+                    (some (fn [t] (seq (:properties (:block/schema t)))) tags))
+               (and
+                (:outliner/block-title-collapse-enabled? (state/get-config))
+                (block-with-title? (:block/format block)
+                                   (:block/content block)
+                                   semantic?))))
          false)))))
 
 (defn all-blocks-with-level

+ 82 - 18
src/main/frontend/handler/page.cljs

@@ -11,7 +11,6 @@
             [frontend.fs :as fs]
             [frontend.handler.common :as common-handler]
             [frontend.handler.common.page :as page-common-handler]
-            [frontend.handler.config :as config-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.plugin :as plugin-handler]
             [frontend.handler.notification :as notification]
@@ -37,13 +36,63 @@
             [electron.ipc :as ipc]
             [frontend.context.i18n :refer [t]]
             [frontend.persist-db.browser :as db-browser]
-            [cljs-bean.core :as bean]))
+            [cljs-bean.core :as bean]
+            [datascript.core :as d]
+            [frontend.db.conn :as conn]
+            [logseq.db :as ldb]
+            [frontend.modules.outliner.ui :as ui-outliner-tx]
+            [logseq.outliner.core :as outliner-core]))
 
 (def create! page-common-handler/create!)
 (def <create! page-common-handler/<create!)
 (def delete! page-common-handler/delete!)
-(def unfavorite-page! page-common-handler/unfavorite-page!)
-(def favorite-page! page-common-handler/favorite-page!)
+
+(defn <unfavorite-page!
+  [page-name]
+  (let [repo (state/get-current-repo)]
+    (if (config/db-based-graph? repo)
+      (let [db (conn/get-db)]
+        (when-let [page-block-uuid (:block/uuid (d/entity db [:block/name (common-util/page-name-sanity-lc page-name)]))]
+          (page-common-handler/<unfavorite-page!-v2 page-block-uuid)))
+      (page-common-handler/unfavorite-page! page-name))))
+
+(defn <favorite-page!
+  [page-name]
+  (let [repo (state/get-current-repo)]
+    (if (config/db-based-graph? repo)
+      (let [db (conn/get-db)]
+        (when-let [page-block-uuid (:block/uuid (d/entity db [:block/name (common-util/page-name-sanity-lc page-name)]))]
+          (page-common-handler/<favorite-page!-v2 page-block-uuid)))
+      (page-common-handler/favorite-page! page-name))))
+
+(defn favorited?
+  [page-name]
+  (let [repo (state/get-current-repo)]
+    (if (config/db-based-graph? repo)
+      (when-let [db (conn/get-db)]
+        (boolean
+         (when-let [page-block-uuid (:block/uuid (d/entity db [:block/name (common-util/page-name-sanity-lc page-name)]))]
+           (page-common-handler/favorited?-v2 page-block-uuid))))
+      (page-common-handler/favorited? page-name))))
+
+
+(defn get-favorites
+  "return page-block entities"
+  []
+  (when-let [db (conn/get-db)]
+    (let [repo (state/get-current-repo)]
+      (if (config/db-based-graph? repo)
+        (let [blocks (ldb/get-page-blocks db page-common-handler/favorites-page-name {})]
+          (keep (fn [block]
+                  (when-let [block-uuid (some-> (:block/content block) parse-uuid)]
+                    (d/entity db [:block/uuid block-uuid]))) blocks))
+        (let [page-names (->> (:favorites (state/sub-config))
+                              (remove string/blank?)
+                              (filter string?)
+                              (mapv util/safe-page-name-sanity-lc)
+                              (distinct))]
+          (keep (fn [page-name] (d/entity db [:block/name page-name])) page-names))))))
+
 
 ;; FIXME: add whiteboard
 (defn- get-directory
@@ -64,12 +113,10 @@
 (defn toggle-favorite! []
   ;; NOTE: in journals or settings, current-page is nil
   (when-let [page-name (state/get-current-page)]
-    (let [favorites  (:favorites (state/sub-config))
-          favorited? (contains? (set (map string/lower-case favorites))
-                                (string/lower-case page-name))]
+    (let [favorited? (favorited? page-name)]
       (if favorited?
-        (unfavorite-page! page-name)
-        (favorite-page! page-name)))))
+        (<unfavorite-page! page-name)
+        (<favorite-page! page-name)))))
 
 (defn rename!
   [old-name new-name & {:as _opts}]
@@ -84,9 +131,24 @@
         (notification/show! "Can't merge whiteboard pages" :error)
         nil))))
 
-(defn reorder-favorites!
+(defn <reorder-favorites!
   [favorites]
-  (config-handler/set-config! :favorites favorites))
+  (let [repo (state/get-current-repo)
+        conn (conn/get-db false)]
+    (when (d/entity @conn [:block/name page-common-handler/favorites-page-name])
+      (let [favorite-page-block-uuid-coll
+            (keep (fn [page-name]
+                    (some-> (d/entity @conn [:block/name (common-util/page-name-sanity-lc page-name)])
+                            :block/uuid
+                            str))
+                  favorites)
+            current-blocks (ldb/get-page-blocks @conn page-common-handler/favorites-page-name {})]
+        (ui-outliner-tx/transact!
+         {}
+         (doseq [[page-block-uuid block] (zipmap favorite-page-block-uuid-coll current-blocks)]
+           (when (not= page-block-uuid (:block/content block))
+             (outliner-core/save-block! repo conn (state/get-date-formatter)
+                                        (assoc block :block/content page-block-uuid)))))))))
 
 (defn has-more-journals?
   []
@@ -201,6 +263,14 @@
     (let [current-selected (util/get-selected-text)]
       (cursor/move-cursor-forward input (+ 2 (count current-selected))))))
 
+(defn add-tag [repo block-id tag & {:keys [tag-entity]}]
+  (let [tag-entity (or tag-entity (db/entity [:block/name (util/page-name-sanity-lc tag)]))
+        tx-data [[:db/add (:db/id tag-entity) :block/type "class"]
+                 [:db/add [:block/uuid block-id] :block/tags (:db/id tag-entity)]
+                 ;; TODO: Should classes counted as refs
+                 [:db/add [:block/uuid block-id] :block/refs (:db/id tag-entity)]]]
+    (db/transact! repo tx-data {:outliner-op :save-block})))
+
 (defn on-chosen-handler
   [input id _q pos format]
   (let [current-pos (cursor/pos input)
@@ -245,13 +315,7 @@
                                             :class? class?}))
                          tag-entity (db/entity [:block/name (util/page-name-sanity-lc tag)])]
                    (when class?
-                     (let [repo (state/get-current-repo)
-                           tag-entity (or tag-entity (db/entity [:block/name (util/page-name-sanity-lc tag)]))
-                           tx-data [[:db/add (:db/id tag-entity) :block/type "class"]
-                                    [:db/add [:block/uuid (:block/uuid edit-block)] :block/tags (:db/id tag-entity)]
-                                    ;; TODO: Should classes counted as refs
-                                    [:db/add [:block/uuid (:block/uuid edit-block)] :block/refs (:db/id tag-entity)]]]
-                       (db/transact! repo tx-data {:outliner-op :save-block})))))))
+                     (add-tag (state/get-current-repo) (:block/uuid edit-block) tag {:tag-entity tag-entity}))))))
            (editor-handler/insert-command! id
                                            (str "#" wrapped-tag)
                                            format

+ 0 - 5
src/main/frontend/handler/property.cljs

@@ -31,13 +31,8 @@
        (set-block-property! repo (:block/uuid page) key value))
       (file-page-property/add-property! page-name key value))))
 
-(defn set-editing-new-property!
-  [value]
-  (state/set-state! :ui/new-property-input-id value))
-
 (defn editing-new-property!
   []
-  (set-editing-new-property! (state/get-edit-input-id))
   (state/clear-edit!))
 
 (defn remove-id-property

+ 2 - 1
src/main/frontend/state.cljs

@@ -112,7 +112,6 @@
                                                false
                                                true)
       :ui/scrolling?                         (atom false)
-      :ui/new-property-input-id              nil
       :document/mode?                        document-mode?
 
       :config                                {}
@@ -131,6 +130,7 @@
       :editor/in-composition?                false
       :editor/content                        (atom {})
       :editor/block                          (atom nil)
+      :editor/properties-container                           (atom nil)
       :editor/block-dom-id                   (atom nil)
       :editor/set-timestamp-block            (atom nil) ;; click rendered block timestamp-cp to set timestamp
       :editor/last-input-time                (atom {})
@@ -1286,6 +1286,7 @@ Similar to re-frame subscriptions"
   (swap! state merge {:editor/last-saved-cursor nil})
   (set-state! :editor/content {})
   (set-state! :editor/block nil)
+  (set-state! :editor/properties-container nil)
   (set-state! :ui/select-query-cache {}))
 
 (defn into-code-editor-mode!

+ 3 - 1
src/main/frontend/worker/pipeline.cljs

@@ -106,7 +106,9 @@
                             ;; TODO: remove this since transact! is really slow
                             (ldb/transact! conn replace-tx {:replace? true
                                                             :pipeline-replace? true}))
-                          tx-report)
+                          (do
+                            (d/store @conn)
+                            tx-report))
               fix-tx-data (validate-and-fix-db! repo conn tx-report context)
               full-tx-data (concat (:tx-data tx-report) fix-tx-data (:tx-data tx-report'))
               final-tx-report (assoc tx-report'

+ 18 - 19
src/test/frontend/db/db_based_model_test.cljs

@@ -5,8 +5,7 @@
             [frontend.test.helper :as test-helper]
             [datascript.core :as d]
             [frontend.handler.db-based.property :as db-property-handler]
-            [frontend.handler.page :as page-handler]
-            [frontend.handler.editor :as editor-handler]))
+            [frontend.handler.page :as page-handler]))
 
 (def repo test-helper/test-db-name-db-version)
 
@@ -52,23 +51,23 @@
     (is (= ["class1" "class2"] (map first (model/get-all-classes repo))))))
 
 (deftest get-class-objects-test
-  (let [opts {:redirect? false :create-first-block? false :class? true}
-        _ (page-handler/create! "class1" opts)
-        class (db/entity [:block/name "class1"])
-        _ (editor-handler/save-block! repo fbid "Block 1 #class1")]
-    (is (= (model/get-class-objects repo (:db/id class))
-           [(:db/id (db/entity [:block/uuid fbid]))]))
+    (let [opts {:redirect? false :create-first-block? false :class? true}
+          _ (page-handler/create! "class1" opts)
+          class (db/entity [:block/name "class1"])
+          _ (test-helper/save-block! repo fbid "Block 1" {:tags ["class1"]})]
+      (is (= (model/get-class-objects repo (:db/id class))
+             [(:db/id (db/entity [:block/uuid fbid]))]))
 
-    (testing "namespace classes"
-      (page-handler/create! "class2" opts)
+      (testing "namespace classes"
+        (page-handler/create! "class2" opts)
       ;; set class2's parent to class1
-      (let [class2 (db/entity [:block/name "class2"])]
-        (db/transact! [{:db/id (:db/id class2)
-                        :block/namespace (:db/id class)}]))
-      (editor-handler/save-block! repo sbid "Block 2 #class2")
-      (is (= (model/get-class-objects repo (:db/id class))
-           [(:db/id (db/entity [:block/uuid fbid]))
-            (:db/id (db/entity [:block/uuid sbid]))])))))
+        (let [class2 (db/entity [:block/name "class2"])]
+          (db/transact! [{:db/id (:db/id class2)
+                          :block/namespace (:db/id class)}]))
+        (test-helper/save-block! repo sbid "Block 2" {:tags ["class2"]})
+        (is (= (model/get-class-objects repo (:db/id class))
+               [(:db/id (db/entity [:block/uuid fbid]))
+                (:db/id (db/entity [:block/uuid sbid]))])))))
 
 (deftest get-classes-with-property-test
   (let [opts {:redirect? false :create-first-block? false :class? true}
@@ -86,8 +85,8 @@
 (deftest get-tag-blocks-test
   (let [opts {:redirect? false :create-first-block? false :class? true}
         _ (page-handler/create! "class1" opts)
-        _ (editor-handler/save-block! repo fbid "Block 1 #class1")
-        _ (editor-handler/save-block! repo sbid "Block 2 #class1")]
+        _ (test-helper/save-block! repo fbid "Block 1" {:tags ["class1"]})
+        _ (test-helper/save-block! repo sbid "Block 2" {:tags ["class1"]})]
     (is
      (= (model/get-tag-blocks repo "class1")
         [(:db/id (db/entity [:block/uuid fbid]))

+ 3 - 3
src/test/frontend/handler/db_based/property_test.cljs

@@ -202,8 +202,8 @@
       (db-property-handler/class-remove-property! repo c1id (:block/uuid (db/entity [:block/name "property-1"])))
       (is (= 1 (count (:properties (:block/schema (db/entity (:db/id c1))))))))
     (testing "Add classes to a block"
-      (editor-handler/save-block! repo fbid "Block 1 #class1 #class2 #class3")
-      (is (= 3 (count (:block/tags (db/entity [:block/uuid fbid]))))))
+        (test-helper/save-block! repo fbid "Block 1" {:tags ["class1" "class2" "class3"]})
+        (is (= 3 (count (:block/tags (db/entity [:block/uuid fbid]))))))
     ;; FIXME: @tiensonqin https://github.com/logseq/logseq/commit/575624c650b2b7e919033a79aa5d14b97507d86f
     #_(testing "Remove a class from a block"
       ;; make sure class2 will not be deleted when removing it from the first block
@@ -291,7 +291,7 @@
       ;; add property
       (db-property-handler/upsert-property! repo k {:type :default} {})
       (let [property (db/entity [:block/name k])
-            last-block-id (db-property-handler/create-property-text-block! fb property "Block content" editor-handler/wrap-parse-block {})
+            {:keys [last-block-id]} (db-property-handler/create-property-text-block! fb property "Block content" editor-handler/wrap-parse-block {})
             {:keys [from-block-id from-property-id]} (db-property-handler/get-property-block-created-block [:block/uuid last-block-id])]
         (is (= from-block-id (:db/id fb)))
         (is (= from-property-id (:db/id property)))))))

+ 11 - 2
src/test/frontend/test/helper.cljs

@@ -8,6 +8,8 @@
             [logseq.db.sqlite.util :as sqlite-util]
             [frontend.db :as db]
             [frontend.date :as date]
+            [frontend.handler.editor :as editor-handler]
+            [frontend.handler.page :as page-handler]
             [datascript.core :as d]
             [logseq.graph-parser.text :as text]))
 
@@ -47,8 +49,8 @@
   [property-lines]
   (->> property-lines
        (keep #(let [[k v] (string/split % #"::\s*" 2)]
-               (when (string/includes? % "::")
-                 [(keyword k) (parse-property-value v)])))
+                (when (string/includes? % "::")
+                  [(keyword k) (parse-property-value v)])))
        (into {})))
 
 (defn- build-block-properties
@@ -256,3 +258,10 @@ This can be called in synchronous contexts as no async fns should be invoked"
                 (start-test-db!))
    :after #(do (state/set-current-repo! nil)
                (destroy-test-db!))})
+
+(defn save-block!
+  "Wrapper around editor-handler/save-block! that also adds tags"
+  [repo block-uuid content {:keys [tags]}]
+  (editor-handler/save-block! repo block-uuid content)
+  (doseq [tag tags]
+    (page-handler/add-tag repo block-uuid tag)))