浏览代码

Merge branch 'feat/db' into refactor/boolean-not-ref-type

Tienson Qin 1 年之前
父节点
当前提交
ea0a26e744

+ 5 - 5
deps/db/src/logseq/db/frontend/property.cljs

@@ -150,23 +150,23 @@
                                               :hide? true
                                               :view-context :page
                                               :public? true}}
-   :logseq.property/table-sorting {:schema
+   :logseq.property.table/sorting {:schema
                                    {:type :coll
                                     :hide? true
                                     :public? false}}
 
-   :logseq.property/table-filters {:schema
+   :logseq.property.table/filters {:schema
                                    {:type :coll
                                     :hide? true
                                     :public? false}}
 
-   :logseq.property/table-hidden-columns {:schema
+   :logseq.property.table/hidden-columns {:schema
                                           {:type :keyword
                                            :cardinality :many
                                            :hide? true
                                            :public? false}}
 
-   :logseq.property/table-ordered-columns {:schema
+   :logseq.property.table/ordered-columns {:schema
                                            {:type :coll
                                             :hide? true
                                             :public? false}}
@@ -201,7 +201,7 @@
 
 (def logseq-property-namespaces
   #{"logseq.property" "logseq.property.tldraw" "logseq.property.pdf" "logseq.task"
-    "logseq.property.linked-references" "logseq.property.asset"})
+    "logseq.property.linked-references" "logseq.property.asset" "logseq.property.table"})
 
 (defn logseq-property?
   "Determines if keyword is a logseq property"

+ 1 - 1
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 10)
+(def version 11)
 ;; 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}

+ 1 - 1
deps/db/src/logseq/db/sqlite/util.cljs

@@ -107,7 +107,7 @@
         (assoc :db/valueType :db.type/ref))))))
 
 (defn build-new-class
-  "Build a standard new class so that it is is consistent across contexts"
+  "Build a standard new class so that it is consistent across contexts"
   [block]
   {:pre [(qualified-keyword? (:db/ident block))]}
   (block-with-timestamps

+ 10 - 9
scripts/src/logseq/tasks/db_graph/create_graph_with_schema_org.cljs

@@ -11,7 +11,6 @@
        type logseq doesnt' support yet
      * schema.org assumes no cardinality. For now, only :node properties are given a :cardinality :many"
   (:require [logseq.outliner.cli :as outliner-cli]
-            [logseq.common.util :as common-util]
             [logseq.db.frontend.property :as db-property]
             [clojure.string :as string]
             [clojure.edn :as edn]
@@ -77,8 +76,8 @@
   {"schema:Integer" :number
    "schema:Float" :number
    "schema:Number" :number
-   "schema:Text_Class" :default
-   "schema:URL_Class" :url
+   "schema:Text" :default
+   "schema:URL" :url
    "schema:Boolean" :checkbox
    "schema:Date" :date})
 
@@ -158,11 +157,11 @@
 
 (defn- get-vector-conflicts
   "Given a seq of tuples returns a seq of tuples that conflict i.e. their first element
-   has a case insensitive conflict/duplicate with another. An example conflict:
-   [[\"schema:businessFunction\" :property] [\"schema:BusinessFunction\" :class]]"
+   has a case sensitive conflict/duplicate with another. An example conflict:
+   [[\"schema:status\" :property] [\"schema:status\" :node]]"
   [tuples-seq]
   (->> tuples-seq
-       (group-by (comp common-util/page-name-sanity-lc first))
+       (group-by first)
        (filter #(> (count (val %)) 1))
        vals))
 
@@ -190,7 +189,8 @@
     (if verbose
       (println "Renaming the following properties because they have names that conflict with Logseq's built in pages"
                (keys renamed-properties) "\n")
-      (println "Renaming" (count renamed-properties) "properties due to page name conflicts"))
+      (when (pos? (count renamed-properties))
+        (println "Renaming" (count renamed-properties) "properties due to page name conflicts")))
     renamed-properties))
 
 (defn- detect-id-conflicts-and-get-renamed-classes
@@ -219,7 +219,8 @@
     (if verbose
       (println "Renaming the following classes because they have property names that conflict with Logseq's case insensitive :block/name:"
                (keys renamed-classes) "\n")
-      (println "Renaming" (count renamed-classes) "classes due to page name conflicts"))
+      (when (pos? (count renamed-classes))
+        (println "Renaming" (count renamed-classes) "classes due to page name conflicts")))
     renamed-classes))
 
 (defn- get-all-properties [schema-data {:keys [verbose]}]
@@ -308,7 +309,7 @@
         select-class-ids
         (if (:subset options)
           ["schema:Person" "schema:CreativeWorkSeries" "schema:Organization"
-           "schema:Movie" "schema:CreativeWork" "schema:Thing"]
+           "schema:Movie" "schema:CreativeWork" "schema:Thing" "schema:Comment"]
           (keys class-map))
         class-to-properties (get-class-to-properties select-class-ids all-properties)
         select-properties (set (mapcat val class-to-properties))

+ 1 - 1
src/main/frontend/common.css

@@ -384,7 +384,7 @@ button.menu:focus {
 
 .menu-link {
   @apply text-popover-foreground/75 select-none hover:text-popover-foreground/100;
-  @apply text-sm px-2 py-1.5 mx-1 hover:rounded transition-opacity duration-150;
+  @apply text-sm px-2 py-1.5 hover:rounded transition-opacity duration-150;
 }
 
 .menu-separator {

+ 18 - 0
src/main/frontend/components/block.css

@@ -204,6 +204,24 @@
 
   &.as-heading {
     @apply flex flex-1;
+
+    h1& {
+      .ui__icon.ti svg {
+        @apply w-8 h-7;
+      }
+    }
+
+    h2& {
+      .ui__icon.ti svg {
+        @apply w-7 h-6;
+      }
+    }
+
+    h3& {
+      .ui__icon.ti svg {
+        @apply w-5 h-5;
+      }
+    }
   }
 
   &:has(.dsl-query), &:has(.embed-page) {

+ 4 - 4
src/main/frontend/components/container.cljs

@@ -545,7 +545,7 @@
                    {:drop (fn [_e files]
                             (when-let [id (state/get-edit-input-id)]
                               (let [format (:block/format (state/get-edit-block))]
-                                (editor-handler/upload-asset id files format editor-handler/*asset-uploading? true))))})
+                                (editor-handler/upload-asset! id files format editor-handler/*asset-uploading? true))))})
                   (common-handler/listen-to-scroll! element)
                   (when (:margin-less-pages? (first (:rum/args state))) ;; makes sure full screen pages displaying without scrollbar
                     (set! (.. element -scrollTop) 0)))
@@ -555,10 +555,10 @@
                      (dnd/unsubscribe! el :upload-files))
                    state)}
   [{:keys [route-match margin-less-pages? route-name indexeddb-support? db-restoring? main-content show-action-bar? show-recording-bar?]}]
-  (let [left-sidebar-open?   (state/sub :ui/left-sidebar-open?)
+  (let [left-sidebar-open? (state/sub :ui/left-sidebar-open?)
         onboarding-and-home? (and (or (nil? (state/get-current-repo)) (config/demo-graph?))
-                                  (not config/publishing?)
-                                  (= :home route-name))
+                               (not config/publishing?)
+                               (= :home route-name))
         margin-less-pages?   (or (and (mobile-util/native-platform?) onboarding-and-home?) margin-less-pages?)]
     [:div#main-container.cp__sidebar-main-layout.flex-1.flex
      {:class (util/classnames [{:is-left-sidebar-open left-sidebar-open?}])}

+ 80 - 250
src/main/frontend/components/editor.cljs

@@ -482,124 +482,6 @@
                (util/stop e)
                (on-submit command @input-value pos)))])))))
 
-(rum/defc absolute-modal < rum/static
-  [cp modal-name set-default-width? {:keys [top left rect]}]
-  (let [MAX-HEIGHT 700
-        MAX-HEIGHT' 600
-        MAX-WIDTH 600
-        SM-MAX-WIDTH 300
-        Y-BOUNDARY-HEIGHT 150
-        vw-width js/window.innerWidth
-        vw-height js/window.innerHeight
-        vw-max-width (- vw-width (:left rect))
-        vw-max-height (- vw-height (:top rect))
-        vw-max-height' (:top rect)
-        sm? (< vw-width 415)
-        max-height (min (- vw-max-height 20) MAX-HEIGHT)
-        max-height' (min (- vw-max-height' 70) MAX-HEIGHT')
-        max-width (if sm? SM-MAX-WIDTH (min (max 400 (/ vw-max-width 2)) MAX-WIDTH))
-        offset-top 24
-        to-max-height (cond-> (if (and (seq rect) (> vw-height max-height))
-                                (let [delta-height (- vw-height (+ (:top rect) top offset-top))]
-                                  (if (< delta-height max-height)
-                                    (- (max (* 2 offset-top) delta-height) 16)
-                                    max-height))
-                                max-height)
-
-                        (= modal-name "commands")
-                        (min 500))
-        right-sidebar? (:ui/sidebar-open? @state/state)
-        editing-key    (state/get-edit-input-id)
-        *el (rum/use-ref nil)
-        y-overflow-vh? (or (< to-max-height Y-BOUNDARY-HEIGHT)
-                           (> (- max-height' to-max-height) Y-BOUNDARY-HEIGHT))
-        to-max-height (if y-overflow-vh? max-height' to-max-height)
-        pos-rect (when (and (seq rect) editing-key)
-                   (:rect (cursor/get-caret-pos (state/get-input))))
-        y-diff (when pos-rect (- (:height pos-rect) (:height rect)))
-        style (merge
-               {:top        (+ top offset-top (if (int? y-diff) y-diff 0))
-                :max-height to-max-height
-                :max-width  700
-                ;; TODO: auto responsive fixed size
-                :width      "fit-content"
-                :z-index    11}
-               (when set-default-width?
-                 {:width max-width})
-               (if (<= vw-max-width (+ left (if set-default-width? max-width 500)))
-                 {:right 0}
-                 {:left 0}))]
-
-    (rum/use-effect!
-     (fn []
-       (when-let [^js/HTMLElement cnt
-                  (and right-sidebar? editing-key
-                       (js/document.querySelector "#main-content-container"))]
-         (when (.contains cnt (js/document.querySelector (str "#" editing-key)))
-           (let [el  (rum/deref *el)
-                 ofx (- (.-scrollWidth cnt) (.-clientWidth cnt))]
-             (when (> ofx 0)
-               (set! (.-transform (.-style el))
-                     (util/format "translate(-%spx, %s)" (+ ofx 20) (if y-overflow-vh? "calc(-100% - 2rem)" 0))))))))
-     [right-sidebar? editing-key y-overflow-vh?])
-
-    ;; HACK: close when click outside for classic editing models (popup)
-    (rum/use-effect!
-      (fn []
-        (let [^js cnt js/document.body
-              handle (fn [^js e]
-                       (when-not (some->> (.-target e) (.contains (rum/deref *el)))
-                         (state/clear-editor-action!)))]
-          (.addEventListener cnt "click" handle false)
-          #(.removeEventListener cnt "click" handle)))
-      [])
-
-    [:div.absolute.rounded-md.shadow-lg.absolute-modal
-     {:ref             *el
-      :data-modal-name modal-name
-      :class           (if y-overflow-vh? "is-overflow-vh-y" "")
-      :on-pointer-down   (fn [e]
-                         (.stopPropagation e))
-      :on-key-down     (fn [^js e]
-                         (case (.-key e)
-                           "Escape"
-                           (do (state/clear-editor-action!)
-                               (some-> (state/get-input)
-                                 (.focus)))
-                           :dune)
-                         (util/stop-propagation e))
-      :style style}
-     cp]))
-
-(rum/defc transition-cp < rum/reactive
-  [cp modal-name set-default-width?]
-  (when-let [pos (:pos (state/sub :editor/action-data))]
-    (ui/css-transition
-      {:class-names "fade"
-       :timeout {:enter 500
-                 :exit 300}}
-      (absolute-modal cp modal-name set-default-width? pos))))
-
-(rum/defc image-uploader < rum/reactive
-  [id format]
-  [:div.image-uploader
-   [:input
-    {:id        "upload-file"
-     :type      "file"
-     :on-change (fn [e]
-                  (let [files (.-files (.-target e))]
-                    (editor-handler/upload-asset id files format editor-handler/*asset-uploading? false)))
-     :hidden    true}]
-   #_:clj-kondo/ignore
-   (when-let [uploading? (util/react editor-handler/*asset-uploading?)]
-     (let [processing (util/react editor-handler/*asset-uploading-process)]
-       (transition-cp
-        [:div.flex.flex-row.align-center.rounded-md.shadow-sm.bg-base-2.px-1.py-1
-         (ui/loading
-          (util/format "Uploading %s%" (util/format "%2d" processing)))]
-        "upload-file"
-        false)))])
-
 (defn- set-up-key-down!
   [state format]
   (mixins/on-key-down
@@ -694,146 +576,98 @@
          [:span {:id (str "mock-text_" idx)
                  :key idx} c])))])
 
-(rum/defc animated-modal < rum/reactive
-  [modal-name component set-default-width?]
-  (when-let [pos (:pos (state/get-editor-action-data))]
-    (ui/css-transition
-     {:key modal-name
-      :class-names {:enter "origin-top-left opacity-0 transform scale-95"
-                    :enter-done "origin-top-left transition opacity-100 transform scale-100"
-                    :exit "origin-top-left transition opacity-0 transform scale-95"}
-      :timeout {:enter 0
-                :exit 150}}
-     (fn [_]
-       (absolute-modal
-        component
-        modal-name
-        set-default-width?
-        pos)))))
-
 (defn- exist-editor-commands-popup?
   []
   (some->> (shui-popup/get-popups)
     (some #(some-> % (:id) (str) (string/starts-with? ":editor.commands")))))
 
-;; TODO: [WIP]
-(rum/defc shui-modals
+(defn- open-editor-popup!
+  [id content opts]
+  (let [{:keys [left top rect]} (cursor/get-caret-pos (state/get-input))
+        pos [(+ left (:left rect) -20) (+ top (:top rect) 20)]
+        {:keys [root-props content-props]} opts]
+    (shui/popup-show!
+      pos content
+      (merge
+        {:id (keyword :editor.commands id)
+         :align :start
+         :root-props (merge {:onOpenChange #(when-not % (state/clear-editor-action!))} root-props)
+         :content-props (merge {:onOpenAutoFocus #(.preventDefault %)
+                                :onCloseAutoFocus #(.preventDefault %)
+                                :data-editor-popup-ref (name id)} content-props)
+         :force-popover? true}
+        (dissoc opts :root-props :content-props)))))
+
+(rum/defc shui-editor-popups
   [id format action _data]
   (rum/use-effect!
     (fn []
-      (let [{:keys [left top rect]} (cursor/get-caret-pos (state/get-input))
-            pos [(+ left (:left rect) -20) (+ top (:top rect) 20)]]
-        (let [pid (case action
-                    :commands
-                    (shui/popup-show! pos
-                      (commands id format)
-                      {:id :editor.commands/commands
-                       :align :start
-                       :root-props {:onOpenChange
-                                    #(when-not %
-                                       (when (= :commands (state/get-editor-action))
-                                         (state/clear-editor-action!)))}
-                       :content-props {:onOpenAutoFocus #(.preventDefault %)
-                                       :onCloseAutoFocus #(.preventDefault %)
-                                       :withoutAnimation true
-                                       :data-editor-popup-ref "commands"}
-                       :force-popover? true})
-
-                    :block-commands
-                    (shui/popup-show! pos
-                      (block-commands id format)
-                      {:id :editor.commands/block-commands
-                       :align :start
-                       :root-props {:onOpenChange
-                                    #(when-not %
-                                       (when (= :block-commands (state/get-editor-action))
-                                         (state/clear-editor-action!)))}
-                       :content-props {:onOpenAutoFocus #(.preventDefault %)
-                                       :onCloseAutoFocus #(.preventDefault %)
-                                       :withoutAnimation true
-                                       :data-editor-popup-ref "commands"}
-                       :force-popover? true})
-
-                    (:block-search :page-search :page-search-hashtag)
-                    (shui/popup-show!
-                      pos (if (= :block-search action)
-                            (block-search id format)
-                            (page-search id format))
-                      {:id :editor.commands/block-search
-                       :align :start
-                       :root-props {:onOpenChange
-                                    #(when-not %
-                                       (when (contains?
-                                               #{:block-search :page-search :page-search-hashtag}
-                                               (state/get-editor-action))
-                                         (state/clear-editor-action!)))}
-                       :content-props {:onOpenAutoFocus #(.preventDefault %)
-                                       :onCloseAutoFocus #(.preventDefault %)
-                                       :data-editor-popup-ref (name action)}
-                       :force-popover? true})
-
-                    :datepicker
-                    (shui/popup-show!
-                      pos (datetime-comp/date-picker id format nil)
-                      {:id :editor.commands/datepicker
-                       :align :start
-                       :root-props {:onOpenChange #(when-not % (state/clear-editor-action!))}
-                       :content-props {:onOpenAutoFocus #(.preventDefault %)
-                                       :data-editor-popup-ref "datepicker"}
-                       :force-popover? true})
-
-                    :input
-                    (shui/popup-show!
-                      pos (input id
-                            (fn [command m]
-                              (editor-handler/handle-command-input command id format m))
-                            (fn []
-                              (editor-handler/handle-command-input-close id)))
-                      {:id :editor.commands/input
-                       :align :start
-                       :root-props {:onOpenChange #(when-not % (state/clear-editor-action!))}
-                       :content-props {:onOpenAutoFocus #(.preventDefault %)
-                                       :onCloseAutoFocus #(.preventDefault %)
-                                       :data-editor-popup-ref "input"}})
-
-                    :select-code-block-mode
-                    (shui/popup-show!
-                      pos (code-block-mode-picker id format)
-                      {:id :editor.commands/code-block-mode-picker
-                       :align :start
-                       :root-props {:onOpenChange #(when-not % (state/clear-editor-action!))}
-                       :content-props {:onOpenAutoFocus #(.preventDefault %)
-                                       :data-editor-popup-ref "code-block-mode-picker"}
-                       :force-popover? true})
-
-                    ;; TODO: try remove local model state
-                    false)]
-          #(when pid
-             (shui/popup-hide! pid)))))
+      (let [pid (case action
+                  :commands
+                  (open-editor-popup! :commands
+                    (commands id format)
+                    {:content-props {:withoutAnimation false}})
+
+                  :block-commands
+                  (open-editor-popup! :block-commands
+                    (block-commands id format)
+                    {:content-props {:withoutAnimation true}})
+
+                  (:block-search :page-search :page-search-hashtag)
+                  (open-editor-popup! action
+                    (if (= :block-search action)
+                      (block-search id format)
+                      (page-search id format))
+                    {:root-props {:onOpenChange
+                                  #(when-not %
+                                     (when (contains?
+                                             #{:block-search :page-search :page-search-hashtag}
+                                             (state/get-editor-action))
+                                       (state/clear-editor-action!)))}})
+
+                  :datepicker
+                  (open-editor-popup! :datepicker
+                    (datetime-comp/date-picker id format nil) {})
+
+                  :input
+                  (open-editor-popup! :input
+                    (input id
+                      (fn [command m]
+                        (editor-handler/handle-command-input command id format m))
+                      (fn []
+                        (editor-handler/handle-command-input-close id))) {})
+
+                  :select-code-block-mode
+                  (open-editor-popup! :code-block-mode-picker
+                    (code-block-mode-picker id format) {})
+
+                  :template-search
+                  (open-editor-popup! :template-search
+                    (template-search id format) {})
+
+                  (:property-search :property-value-search)
+                  (open-editor-popup! action
+                    (if (= :property-search action)
+                      (property-search id) (property-value-search id))
+                    {})
+
+                  :zotero
+                  (open-editor-popup! :zotero
+                    (zotero/zotero-search id) {})
+
+                  ;; TODO: try remove local model state
+                  false)]
+        #(when pid
+           (shui/popup-hide! pid))))
     [action])
   [:<>])
 
-(rum/defc modals < rum/reactive
-  "React to atom changes, find and render the correct modal"
+(rum/defc command-popups <
+  rum/reactive
+  "React to atom changes, find and render the correct popup"
   [id format]
   (let [action (state/sub :editor/action)]
-    [:<>
-     (shui-modals id format action nil)
-     (cond
-       (= :template-search action)
-       (animated-modal "template-search" (template-search id format) true)
-
-       (= :property-search action)
-       (animated-modal "property-search" (property-search id) true)
-
-       (= :property-value-search action)
-       (animated-modal "property-value-search" (property-value-search id) true)
-
-       (= :zotero action)
-       (animated-modal "zotero-search" (zotero/zotero-search id) false)
-
-       :else
-       nil)]))
+    (shui-editor-popups id format action nil)))
 
 (defn- editor-on-hide
   [state value* type e]
@@ -916,9 +750,5 @@
     [:div.editor-inner.flex.flex-1 {:class (if block "block-editor" "non-block-editor")}
 
      (ui/ls-textarea opts)
-
      (mock-textarea content)
-     (modals id format)
-
-     (when format
-       (image-uploader id format))]))
+     (command-popups id format)]))

+ 3 - 3
src/main/frontend/components/editor.css

@@ -73,7 +73,7 @@ pre {
 
 .ui__popover-content, .ui__dropdown-menu-content {
   &[data-editor-popup-ref] {
-    @apply p-1 w-72;
+    @apply p-1.5 w-72;
 
     &[data-side=top] {
       position: relative;
@@ -82,7 +82,7 @@ pre {
   }
 
   &[data-editor-popup-ref=commands] {
-    @apply px-1 py-1 w-72;
+    @apply w-72;
 
     &[data-side=top] {
       max-height: min(calc(var(--radix-popover-content-available-height) - 60px), 460px);
@@ -96,7 +96,7 @@ pre {
   &[data-editor-popup-ref=page-search],
   &[data-editor-popup-ref=block-search],
   &[data-editor-popup-ref=page-search-hashtag] {
-    @apply px-1 py-1 w-full sm:w-128;
+    @apply w-full sm:w-128;
   }
 
   &[data-editor-popup-ref=datepicker] {

+ 1 - 1
src/main/frontend/components/file_based/block.cljs

@@ -40,7 +40,7 @@
     (when class
       (ui/checkbox {:class class
                     :style {:margin-right 5}
-                    :value checked?
+                    :checked checked?
                     :on-pointer-down (fn [e]
                                        (util/stop-propagation e))
                     :on-change (fn [_e]

+ 5 - 3
src/main/frontend/components/property/value.cljs

@@ -70,14 +70,16 @@
           (if (and (= :default (get-in property [:block/schema :type]))
                    (not (db-property/many? property)))
             (p/let [existing-value (get block (:db/ident property))
-                    new-block-id (when-not existing-value (db/new-block-id))
-                    _ (when-not existing-value
+                    existing-value? (and (some? existing-value)
+                                         (not= (:db/ident existing-value) :logseq.property/empty-placeholder))
+                    new-block-id (when-not existing-value? (db/new-block-id))
+                    _ (when-not existing-value?
                         (db-property-handler/create-property-text-block!
                          (:db/id block)
                          (:db/id property)
                          value
                          {:new-block-id new-block-id}))]
-              (or existing-value (db/entity [:block/uuid new-block-id])))
+              (if existing-value? existing-value (db/entity [:block/uuid new-block-id])))
             (p/let [new-block-id (db/new-block-id)
                     _ (db-property-handler/create-property-text-block!
                        (:db/id block)

+ 4 - 17
src/main/frontend/components/repo.css

@@ -16,27 +16,15 @@
 
 .ui__dropdown-menu-content {
   &.repos-list {
-    @apply px-2 pb-[210px] relative overflow-hidden;
-    @apply min-w-[280px] sm:max-w-[320px] max-h-[66vh];
-
-    &.no-repos {
-      @apply pb-[180px];
-    }
-
-    &[data-mode=db] {
-      @apply pb-[114px];
-
-      &.no-repos {
-        @apply pb-[109px];
-      }
-    }
+    @apply px-2 relative overflow-hidden;
+    @apply min-w-[280px] sm:max-w-[320px];
 
     .ui__dropdown-menu-item {
       @apply overflow-hidden overflow-ellipsis;
     }
 
     .cp__repos-list-wrap {
-      @apply max-h-96 overflow-scroll m-[-8px] px-2 pb-6;
+      @apply max-h-80 overflow-scroll mx-[-8px] px-2 pb-2;
     }
   }
 }
@@ -64,8 +52,7 @@
 }
 
 .cp__repos-quick-actions {
-  @apply absolute left-[1px] right-[1px] bottom-[1px] bg-gray-01 px-2 py-3 border-t
-  flex flex-col rounded-b overflow-hidden;
+  @apply -mx-2 bg-gray-01 px-2 pb-1.5 pt-3 border-t flex flex-col rounded-b overflow-hidden;
 
   .ui__button {
     @apply w-full !py-4 !justify-start opacity-70 font-medium hover:opacity-90

+ 9 - 9
src/main/frontend/components/views.cljs

@@ -95,7 +95,7 @@
   [block property]
   (let [type (get-in property [:block/schema :type])
         many? (= :db.cardinality/many (get property :db/cardinality))
-        ref-types (into db-property-type/value-ref-property-types #{:entity})
+        ref-types (into db-property-type/ref-property-types #{:entity})
         number-type? (= :number type)
         v (get block (:db/ident property))
         v' (if many? v [v])
@@ -871,13 +871,13 @@
      (fn [sorting]
        (set-sorting! sorting)
        (p/let [entity (or entity (create-view!))]
-         (property-handler/set-block-property! repo (:db/id entity) :logseq.property/table-sorting sorting)))
+         (property-handler/set-block-property! repo (:db/id entity) :logseq.property.table/sorting sorting)))
      :set-filters!
      (fn [filters]
        (let [filters (table-filters->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?]]
@@ -885,24 +885,24 @@
                                            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 view-inner < rum/static
   [view-entity {:keys [data set-data! columns add-new-object! create-view! title-key] :as option}]
   (let [[input set-input!] (rum/use-state "")
-        sorting (:logseq.property/table-sorting view-entity)
+        sorting (:logseq.property.table/sorting view-entity)
         [sorting set-sorting!] (rum/use-state (or sorting [{:id :block/updated-at, :asc? false}]))
-        filters (:logseq.property/table-filters view-entity)
+        filters (:logseq.property.table/filters view-entity)
         [filters set-filters!] (rum/use-state (or filters []))
-        hidden-columns (:logseq.property/table-hidden-columns view-entity)
+        hidden-columns (:logseq.property.table/hidden-columns view-entity)
         [visible-columns set-visible-columns!] (rum/use-state (zipmap hidden-columns (repeat false)))
-        ordered-columns (vec (concat [:select] (:logseq.property/table-ordered-columns view-entity)))
+        ordered-columns (vec (concat [:select] (:logseq.property.table/ordered-columns view-entity)))
         [ordered-columns set-ordered-columns!] (rum/use-state ordered-columns)
         {:keys [set-sorting! set-filters! set-visible-columns! set-ordered-columns!]}
         (db-set-table-state! view-entity {:set-sorting! set-sorting!

+ 1 - 1
src/main/frontend/handler/editor.cljs

@@ -1535,7 +1535,7 @@
       (path/get-relative-path current-file-fpath file-path))
     file-path))
 
-(defn upload-asset
+(defn upload-asset!
   "Paste asset and insert link to current editing block"
   [id ^js files format uploading? drop-or-paste?]
   (let [repo (state/get-current-repo)]

+ 0 - 14
src/main/frontend/handler/events.cljs

@@ -56,7 +56,6 @@
             [frontend.handler.user :as user-handler]
             [frontend.handler.property.util :as pu]
             [frontend.handler.db-based.property.util :as db-pu]
-            [frontend.handler.file-based.property.util :as property-util]
             [frontend.handler.property :as property-handler]
             [frontend.handler.file-based.nfs :as nfs-handler]
             [frontend.handler.code :as code-handler]
@@ -846,19 +845,6 @@
 (defmethod handle :graph/save-db-to-disk [[_ _opts]]
   (persist-db/export-current-graph! {:succ-notification? true}))
 
-(defmethod handle :search/transact-data [[_ repo data]]
-  (let [file-based? (config/local-file-based-graph? repo)
-        data' (cond-> data
-                file-based?
-                ;; remove built-in properties from content
-                (update :blocks-to-add
-                  (fn [blocks]
-                    (map #(update % :content
-                            (fn [content]
-                              (property-util/remove-built-in-properties (get % :format :markdown) content)))
-                      blocks))))]
-    (search/transact-blocks! repo data')))
-
 (defmethod handle :class/configure [[_ page]]
   (shui/dialog-open!
     #(vector :<>

+ 1 - 1
src/main/frontend/handler/paste.cljs

@@ -220,7 +220,7 @@
           files (.-files clipboard-data)]
       (when-let [file (first files)]
         (when-let [block (state/get-edit-block)]
-          (editor-handler/upload-asset id #js[file] (:block/format block)
+          (editor-handler/upload-asset! id #js[file] (:block/format block)
                                        editor-handler/*asset-uploading? true)))
       (util/stop e))))
 

+ 9 - 1
src/main/frontend/handler/plugin.cljs

@@ -252,10 +252,18 @@
 
     (js/window.apis.addListener channel listener)))
 
+(defn- normalize-plugin-metadata
+  [metadata]
+  (cond-> metadata
+    (not (string? (:author metadata)))
+    (assoc :author (or (get-in metadata [:author :name]) ""))))
+
 (defn register-plugin
   [plugin-metadata]
   (when-let [pid (keyword (:id plugin-metadata))]
-    (swap! state/state update-in [:plugin/installed-plugins] assoc pid plugin-metadata)))
+    (some->> plugin-metadata
+      (normalize-plugin-metadata)
+      (swap! state/state update-in [:plugin/installed-plugins] assoc pid))))
 
 (defn host-mounted!
   []

+ 0 - 5
src/main/frontend/search.cljs

@@ -106,11 +106,6 @@
   (when-let [engine (get-engine repo)]
     (protocol/remove-db! engine)))
 
-(defn transact-blocks!
-  [repo data]
-  (when-let [engine (get-engine repo)]
-    (protocol/transact-blocks! engine data)))
-
 (defn get-unlinked-refs
   "Get matched result from search first, and then filter by worker db"
   [eid]

+ 22 - 1
src/main/frontend/worker/db/migrate.cljs

@@ -72,6 +72,26 @@
                        datoms)]
     (concat schema-tx-data value-tx-data)))
 
+(defn- update-table-properties
+  [conn _search-db]
+  (let [old-new-props {:logseq.property/table-sorting :logseq.property.table/sorting
+                       :logseq.property/table-filters :logseq.property.table/filters
+                       :logseq.property/table-ordered-columns :logseq.property.table/ordered-columns
+                       :logseq.property/table-hidden-columns :logseq.property.table/hidden-columns}
+        props-tx (mapv (fn [[old new]]
+                         {:db/id (:db/id (d/entity @conn old))
+                          :db/ident new})
+                       old-new-props)]
+    ;; Property changes need to be in their own tx for subsequent uses of properties to take effect
+    (ldb/transact! conn props-tx {:db-migrate? true})
+
+    (mapcat (fn [[old new]]
+              (->> (d/q '[:find ?b ?prop-v :in $ ?prop :where [?b ?prop ?prop-v]] @conn old)
+                   (mapcat (fn [[id prop-value]]
+                             [[:db/retract id old]
+                              [:db/add id new prop-value]]))))
+            old-new-props)))
+
 (def schema-version->updates
   [[3 {:properties [:logseq.property/table-sorting :logseq.property/table-filters
                     :logseq.property/table-hidden-columns :logseq.property/table-ordered-columns]
@@ -88,7 +108,8 @@
    [7 {:fix replace-original-name-content-with-title}]
    [8 {:fix replace-object-and-page-type-with-node}]
    [9 {:fix update-task-ident}]
-   [10 {:fix property-checkbox-type-non-ref}]])
+   [10 {:fix update-table-properties}]
+   [11 {:fix property-checkbox-type-non-ref}]])
 
 (let [max-schema-version (apply max (map first schema-version->updates))]
   (assert (<= db-schema/version max-schema-version))

+ 1 - 1
src/main/frontend/worker/rtc/client_op.cljs

@@ -85,7 +85,7 @@
     (if (> t1 t2)
       (merge-update-ops update-op2 update-op1)
       (let [{av-coll1 :av-coll block-uuid :block-uuid} (last update-op1)
-            {av-coll2 :av-coll} (last update-op1)]
+            {av-coll2 :av-coll} (last update-op2)]
         [:update t2
          {:block-uuid block-uuid
           :av-coll (concat av-coll1 av-coll2)}]))))

+ 1 - 1
src/test/frontend/handler/paste_test.cljs

@@ -241,7 +241,7 @@
       reset
       [state/preferred-pasting-file? (constantly true)
        ;; paste-file-if-exists mocks below
-       editor-handler/upload-asset (fn [_id file & _]
+       editor-handler/upload-asset! (fn [_id file & _]
                                      (reset! pasted-file file))
        util/stop (constantly nil)
        state/get-edit-block (constantly {})]

+ 22 - 18
src/test/logseq/api_test.cljs

@@ -12,28 +12,32 @@
 (deftest get-block
   (with-redefs [state/get-current-repo (constantly test-helper/test-db)]
     (db/transact! test-helper/test-db
-                  [{:db/id 10000
-                    :block/uuid #uuid "4406f839-6410-43b5-87db-25e9b8f54cc0"
-                    :block/title "1"}
-                   {:db/id 10001
-                    :block/uuid #uuid "d9b7b45f-267f-4794-9569-f43d1ce77172"
-                    :block/title "2"}
-                   {:db/id 10002
-                    :block/uuid #uuid "adae3006-f03e-4814-a1f5-f17f15b86556"
-                    :block/parent 10001
-                    :block/title "3"}
-                   {:db/id 10003
-                    :block/uuid #uuid "0c3053c3-2dab-4769-badd-14ce16d8ba8d"
-                    :block/parent 10002
-                    :block/title "4"}])
+      [{:db/id 10000
+        :block/uuid #uuid "4406f839-6410-43b5-87db-25e9b8f54cc0"
+        :block/title "1"}
+       {:db/id 10001
+        :block/uuid #uuid "d9b7b45f-267f-4794-9569-f43d1ce77172"
+        :block/title "2"}
+       {:db/id 10002
+        :block/uuid #uuid "adae3006-f03e-4814-a1f5-f17f15b86556"
+        :block/parent 10001
+        :block/title "3"}
+       {:db/id 10003
+        :block/uuid #uuid "0c3053c3-2dab-4769-badd-14ce16d8ba8d"
+        :block/parent 10002
+        :block/title "4"}])
 
     (is (= (:title (bean/->clj (api-block/get_block 10000 #js {}))) "1"))
     (is (= (:title (bean/->clj (api-block/get_block "d9b7b45f-267f-4794-9569-f43d1ce77172" #js {}))) "2"))
     (is (= (:title (bean/->clj (api-block/get_block #uuid "d9b7b45f-267f-4794-9569-f43d1ce77172" #js {}))) "2"))
     (is (= {:id 10001, :title "2", :uuid "d9b7b45f-267f-4794-9569-f43d1ce77172", :children [["uuid" "adae3006-f03e-4814-a1f5-f17f15b86556"]]}
-           (select-keys (js->clj (api-block/get_block 10001 #js {:includeChildren false}) :keywordize-keys true)
-                        [:id :title :uuid :children])))
-    (is (= {:title "2", :uuid "d9b7b45f-267f-4794-9569-f43d1ce77172", :id 10001, :children [{:title "3", :parent {:id 10001}, :uuid "adae3006-f03e-4814-a1f5-f17f15b86556", :id 10002, :level 1, :children [{:title "4", :parent {:id 10002}, :uuid "0c3053c3-2dab-4769-badd-14ce16d8ba8d", :id 10003, :level 2, :children []}]}]}
-           (js->clj (api-block/get_block 10001 #js {:includeChildren true}) :keywordize-keys true)))))
+          (select-keys (js->clj (api-block/get_block 10001 #js {:includeChildren false}) :keywordize-keys true)
+            [:id :title :uuid :children])))
+    ;; NOTE: `content` key is to be compatible with old APIs
+    (is (= {:id 10001, :title "2", :content "2" :uuid "d9b7b45f-267f-4794-9569-f43d1ce77172"
+            :children [{:id 10002 :title "3", :content "3"
+                        :parent {:id 10001}, :uuid "adae3006-f03e-4814-a1f5-f17f15b86556", :level 1,
+                        :children [{:id 10003, :title "4", :content "4" :parent {:id 10002}, :uuid "0c3053c3-2dab-4769-badd-14ce16d8ba8d", :level 2, :children []}]}]}
+          (js->clj (api-block/get_block 10001 #js {:includeChildren true}) :keywordize-keys true)))))
 
 #_(cljs.test/run-tests)