Переглянути джерело

Merge branch 'feat/db' into refactor/db-properties-schema

Tienson Qin 1 рік тому
батько
коміт
958507262e
81 змінених файлів з 1679 додано та 1254 видалено
  1. 2 2
      .github/workflows/build-desktop-release.yml
  2. 1 1
      .github/workflows/db.yml
  3. 2 2
      capacitor.config.ts
  4. 2 2
      deps.edn
  5. 2 1
      deps/db/src/logseq/db.cljs
  6. 7 9
      deps/db/src/logseq/db/frontend/class.cljs
  7. 23 10
      deps/db/src/logseq/db/frontend/malli_schema.cljs
  8. 183 169
      deps/db/src/logseq/db/frontend/property.cljs
  9. 7 0
      deps/db/src/logseq/db/frontend/rules.cljc
  10. 4 4
      deps/db/src/logseq/db/frontend/schema.cljs
  11. 2 2
      deps/db/src/logseq/db/sqlite/common_db.cljs
  12. 21 23
      deps/db/src/logseq/db/sqlite/create_graph.cljs
  13. 4 3
      deps/db/src/logseq/db/sqlite/db.cljs
  14. 0 1
      deps/db/test/logseq/db/sqlite/common_db_test.cljs
  15. 55 26
      deps/db/test/logseq/db/sqlite/create_graph_test.cljs
  16. 20 10
      deps/graph-parser/src/logseq/graph_parser/exporter.cljs
  17. 2 2
      deps/graph-parser/src/logseq/graph_parser/whiteboard.cljs
  18. 2 2
      deps/outliner/src/logseq/outliner/core.cljs
  19. 4 3
      deps/shui/src/logseq/shui/dialog/core.cljs
  20. 3 0
      deps/shui/src/logseq/shui/popup/core.cljs
  21. 2 2
      e2e-tests/utils.ts
  22. 1 2
      package.json
  23. 3 0
      packages/ui/@/components/ui/dropdown-menu.tsx
  24. 3 1
      packages/ui/@/components/ui/popover.tsx
  25. 2 2
      packages/ui/src/vars-classic.css
  26. 2 1
      resources/forge.config.js
  27. 6 6
      resources/package.json
  28. 1 1
      scripts/src/logseq/tasks/db_graph/create_graph_with_properties.cljs
  29. 2 2
      scripts/src/logseq/tasks/db_graph/create_graph_with_schema_org.cljs
  30. 1 0
      src/main/frontend/common.css
  31. 27 25
      src/main/frontend/components/block.cljs
  32. 1 1
      src/main/frontend/components/block/macros.cljs
  33. 39 11
      src/main/frontend/components/class.cljs
  34. 2 2
      src/main/frontend/components/container.cljs
  35. 6 2
      src/main/frontend/components/container.css
  36. 1 1
      src/main/frontend/components/content.cljs
  37. 1 1
      src/main/frontend/components/editor.cljs
  38. 85 61
      src/main/frontend/components/header.cljs
  39. 0 5
      src/main/frontend/components/header.css
  40. 20 58
      src/main/frontend/components/hierarchy.cljs
  41. 2 8
      src/main/frontend/components/journal.css
  42. 55 12
      src/main/frontend/components/page.css
  43. 2 3
      src/main/frontend/components/page_menu.cljs
  44. 2 2
      src/main/frontend/components/plugins.cljs
  45. 3 8
      src/main/frontend/components/plugins.css
  46. 99 80
      src/main/frontend/components/property.cljs
  47. 1 1
      src/main/frontend/components/property.css
  48. 5 5
      src/main/frontend/components/query_table.cljs
  49. 134 103
      src/main/frontend/components/repo.cljs
  50. 19 2
      src/main/frontend/components/repo.css
  51. 1 1
      src/main/frontend/config.cljs
  52. 13 7
      src/main/frontend/db/async.cljs
  53. 7 7
      src/main/frontend/db/model.cljs
  54. 71 60
      src/main/frontend/db/rtc/debug_ui.cljs
  55. 35 8
      src/main/frontend/db_worker.cljs
  56. 7 7
      src/main/frontend/extensions/pdf/assets.cljs
  57. 1 1
      src/main/frontend/extensions/pdf/utils.cljs
  58. 2 2
      src/main/frontend/handler/block.cljs
  59. 3 2
      src/main/frontend/handler/db_based/editor.cljs
  60. 12 12
      src/main/frontend/handler/db_based/property.cljs
  61. 3 4
      src/main/frontend/handler/db_based/property/util.cljs
  62. 33 12
      src/main/frontend/handler/db_based/rtc.cljs
  63. 4 4
      src/main/frontend/handler/editor.cljs
  64. 6 6
      src/main/frontend/handler/events.cljs
  65. 1 1
      src/main/frontend/handler/graph.cljs
  66. 2 3
      src/main/frontend/handler/page.cljs
  67. 25 9
      src/main/frontend/handler/property/util.cljs
  68. 1 1
      src/main/frontend/handler/route.cljs
  69. 7 9
      src/main/frontend/handler/user.cljs
  70. 10 10
      src/main/frontend/handler/whiteboard.cljs
  71. 5 7
      src/main/frontend/search.cljs
  72. 3 2
      src/main/frontend/shui.cljs
  73. 16 0
      src/main/frontend/worker/rtc/const.cljs
  74. 62 47
      src/main/frontend/worker/rtc/core.cljs
  75. 79 14
      src/main/frontend/worker/rtc/full_upload_download_graph.cljs
  76. 1 2
      src/main/logseq/api.cljs
  77. 5 5
      src/test/frontend/db/db_based_model_test.cljs
  78. 3 4
      src/test/frontend/handler/db_based/property_test.cljs
  79. 31 1
      src/test/frontend/worker/rtc/rtc_fns_test.cljs
  80. 353 317
      static/yarn.lock
  81. 4 9
      yarn.lock

+ 2 - 2
.github/workflows/build-desktop-release.yml

@@ -392,7 +392,7 @@ jobs:
         env:
         env:
           APPLE_ID: ${{ secrets.APPLE_ID_EMAIL }}
           APPLE_ID: ${{ secrets.APPLE_ID_EMAIL }}
           APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
           APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
-          APPLE_ASC_PROVIDER: ${{ secrets.APPLE_ASC_PROVIDER }}
+          APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
 
 
       - name: Save x64 artifacts
       - name: Save x64 artifacts
         run: |
         run: |
@@ -469,7 +469,7 @@ jobs:
         env:
         env:
           APPLE_ID: ${{ secrets.APPLE_ID_EMAIL }}
           APPLE_ID: ${{ secrets.APPLE_ID_EMAIL }}
           APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
           APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
-          APPLE_ASC_PROVIDER: ${{ secrets.APPLE_ASC_PROVIDER }}
+          APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
 
 
       - name: Save arm64 artifacts
       - name: Save arm64 artifacts
         run: |
         run: |

+ 1 - 1
.github/workflows/db.yml

@@ -83,7 +83,7 @@ jobs:
           bb: ${{ env.BABASHKA_VERSION }}
           bb: ${{ env.BABASHKA_VERSION }}
 
 
       - name: Run clj-kondo lint
       - name: Run clj-kondo lint
-        run: clojure -M:clj-kondo --parallel --lint src
+        run: clojure -M:clj-kondo --lint src test
 
 
       - name: Carve lint for unused vars
       - name: Carve lint for unused vars
         run: bb lint:carve 2>/dev/null
         run: bb lint:carve 2>/dev/null

+ 2 - 2
capacitor.config.ts

@@ -40,10 +40,10 @@ const config: CapacitorConfig = {
   }
   }
 }
 }
 
 
-if (process.env.LOGSEQ_APP_SERVER_URL) {
+if ("http://192.168.199.216:3001") {
   Object.assign(config, {
   Object.assign(config, {
     server: {
     server: {
-      url: process.env.LOGSEQ_APP_SERVER_URL,
+      url: "http://192.168.199.216:3001",
       cleartext: true
       cleartext: true
     }
     }
   })
   })

+ 2 - 2
deps.edn

@@ -42,7 +42,7 @@
  :aliases {:cljs {:extra-paths ["src/dev-cljs/" "src/test/" "src/electron/"]
  :aliases {:cljs {:extra-paths ["src/dev-cljs/" "src/test/" "src/electron/"]
                   :extra-deps  {org.clojure/clojurescript        {:mvn/version "1.11.54"}
                   :extra-deps  {org.clojure/clojurescript        {:mvn/version "1.11.54"}
                                 org.clojure/tools.namespace      {:mvn/version "0.2.11"}
                                 org.clojure/tools.namespace      {:mvn/version "0.2.11"}
-                                cider/cider-nrepl                {:mvn/version "0.44.0"}
+                                cider/cider-nrepl                {:mvn/version "0.47.0"}
                                 org.clojars.knubie/cljs-run-test {:mvn/version "1.0.1"}
                                 org.clojars.knubie/cljs-run-test {:mvn/version "1.0.1"}
                                 tortue/spy                       {:mvn/version "2.14.0"}}
                                 tortue/spy                       {:mvn/version "2.14.0"}}
                   :main-opts   ["-m" "shadow.cljs.devtools.cli"]}
                   :main-opts   ["-m" "shadow.cljs.devtools.cli"]}
@@ -53,7 +53,7 @@
                                 pjstadig/humane-test-output      {:mvn/version "0.11.0"}
                                 pjstadig/humane-test-output      {:mvn/version "0.11.0"}
                                 org.clojars.knubie/cljs-run-test {:mvn/version "1.0.1"}
                                 org.clojars.knubie/cljs-run-test {:mvn/version "1.0.1"}
                                 tortue/spy                       {:mvn/version "2.14.0"}
                                 tortue/spy                       {:mvn/version "2.14.0"}
-                                cider/cider-nrepl                {:mvn/version "0.44.0"}}
+                                cider/cider-nrepl                {:mvn/version "0.47.0"}}
                   :main-opts   ["-m" "shadow.cljs.devtools.cli"]}
                   :main-opts   ["-m" "shadow.cljs.devtools.cli"]}
 
 
            :bench {:extra-paths ["src/bench/"]
            :bench {:extra-paths ["src/bench/"]

+ 2 - 1
deps/db/src/logseq/db.cljs

@@ -41,6 +41,7 @@
     ;; TODO: remove this in later releases
     ;; TODO: remove this in later releases
     :block/heading-level
     :block/heading-level
     :block/file
     :block/file
+    :class/parent
     {:block/page [:db/id :block/name :block/original-name :block/journal-day]}
     {:block/page [:db/id :block/name :block/original-name :block/journal-day]}
     {:block/_parent ...}])
     {:block/_parent ...}])
 
 
@@ -599,7 +600,7 @@
 
 
 (defn get-graph-rtc-uuid
 (defn get-graph-rtc-uuid
   [db]
   [db]
-  (when db (:graph/uuid (d/entity db :graph/uuid))))
+  (when db (:graph/uuid (d/entity db :logseq.kv/graph-uuid))))
 
 
 (comment
 (comment
   (defn db-based-graph?
   (defn db-based-graph?

+ 7 - 9
deps/db/src/logseq/db/frontend/class.cljs

@@ -1,15 +1,13 @@
 (ns logseq.db.frontend.class
 (ns logseq.db.frontend.class
   "Class related fns for DB graphs and frontend/datascript usage")
   "Class related fns for DB graphs and frontend/datascript usage")
 
 
-;; TODO: disable name changes for those built-in page/class names and their properties names
 (def ^:large-vars/data-var built-in-classes
 (def ^:large-vars/data-var built-in-classes
-  {:task {:original-name "Task"
-          :schema {:properties #{:logseq.property/status
-                                 :logseq.property/priority
-                                 :logseq.property/scheduled
-                                 :logseq.property/deadline}}}
-   :card {:original-name "card"
-          ;; :schema {:property []}
-          }
+  "Map of built-in classes for db graphs with their :db/ident as keys"
+  {:logseq.class/task
+   {:original-name "Task"
+    :schema {:properties [:logseq.task/status :logseq.task/priority :logseq.task/scheduled :logseq.task/deadline]}}
+   :logseq.class/card {:original-name "card"
+                       ;; :schema {:property []}
+                       }
    ;; TODO: Add more classes such as :book, :paper, :movie, :music, :project
    ;; TODO: Add more classes such as :book, :paper, :movie, :music, :project
    })
    })

+ 23 - 10
deps/db/src/logseq/db/frontend/malli_schema.cljs

@@ -90,6 +90,7 @@
    [:block/original-name :string]
    [:block/original-name :string]
    [:block/type {:optional true} [:enum #{"property"} #{"class"} #{"whiteboard"} #{"hidden"}]]
    [:block/type {:optional true} [:enum #{"property"} #{"class"} #{"whiteboard"} #{"hidden"}]]
    [:block/journal? :boolean]
    [:block/journal? :boolean]
+   [:block/namespace {:optional true} :int]
    [:block/alias {:optional true} [:set :int]]
    [:block/alias {:optional true} [:set :int]]
     ;; TODO: Should this be here or in common?
     ;; TODO: Should this be here or in common?
    [:block/path-refs {:optional true} [:set :int]]])
    [:block/path-refs {:optional true} [:set :int]]])
@@ -101,20 +102,31 @@
      ;; Only for linked pages
      ;; Only for linked pages
      [:block/collapsed? {:optional true} :boolean]
      [:block/collapsed? {:optional true} :boolean]
      ;; journal-day is only set for journal pages
      ;; journal-day is only set for journal pages
-     [:block/journal-day {:optional true} :int]
-     [:block/namespace {:optional true} :int]]
+     [:block/journal-day {:optional true} :int]]
     page-attrs
     page-attrs
     page-or-block-attrs)))
     page-or-block-attrs)))
 
 
 (def class-attrs
 (def class-attrs
   [[:db/ident {:optional true} :keyword]
   [[:db/ident {:optional true} :keyword]
+   [:class/parent {:optional true} :int]
    [:class/schema.properties {:optional true} [:set :int]]])
    [:class/schema.properties {:optional true} [:set :int]]])
 
 
+(def logseq-ident-namespaces
+  "Set of all namespaces Logseq uses for :db/ident. It's important to grow this
+  list purposefully and have it start with 'logseq' to allow for users and 3rd
+  party plugins to provide their own namespaces to core concepts."
+  #{"logseq.property" "logseq.property.table" "logseq.property.tldraw"
+    "logseq.class" "logseq.task" "logseq.kv"})
+
+(def logseq-ident
+  [:and :keyword [:fn
+                  {:error/message "should be a valid :db/ident namespace"}
+                  (fn logseq-namespace? [k]
+                    (contains? logseq-ident-namespaces (namespace k)))]])
 (def class-page
 (def class-page
   (vec
   (vec
    (concat
    (concat
     [:map
     [:map
-     [:block/namespace {:optional true} :int]
      [:block/schema
      [:block/schema
       {:optional true}
       {:optional true}
       [:map
       [:map
@@ -143,13 +155,15 @@
   (vec
   (vec
    (concat
    (concat
     [:map
     [:map
-     [:db/ident :keyword]
+     [:db/ident logseq-ident]
      [:block/schema
      [:block/schema
       (vec
       (vec
        (concat
        (concat
         [:map
         [:map
          [:type (apply vector :enum (into db-property-type/internal-built-in-property-types
          [:type (apply vector :enum (into db-property-type/internal-built-in-property-types
-                                          db-property-type/user-built-in-property-types))]]
+                                          db-property-type/user-built-in-property-types))]
+         [:public? {:optional true} :boolean]
+         [:view-context {:optional true} [:enum :page :block]]]
         property-common-schema-attrs
         property-common-schema-attrs
         property-type-schema-attrs))]]
         property-type-schema-attrs))]]
     page-attrs
     page-attrs
@@ -235,7 +249,7 @@
     [:map]
     [:map]
     [[:block/type [:= #{"closed value"}]]
     [[:block/type [:= #{"closed value"}]]
      ;; for built-in properties
      ;; for built-in properties
-     [:db/ident {:optional true} :keyword]
+     [:db/ident {:optional true} logseq-ident]
      [:block/schema {:optional true}
      [:block/schema {:optional true}
       [:map
       [:map
        [:value [:or :string :double]]
        [:value [:or :string :double]]
@@ -283,7 +297,7 @@
   (into [:or]
   (into [:or]
         (map (fn [kv]
         (map (fn [kv]
                [:map
                [:map
-                [:db/ident :keyword]
+                [:db/ident logseq-ident]
                 kv
                 kv
                 [:block/tx-id {:optional true} :int]])
                 [:block/tx-id {:optional true} :int]])
              db-ident-keys)))
              db-ident-keys)))
@@ -337,9 +351,8 @@
                                        db-ident-keys (rest class-page))
                                        db-ident-keys (rest class-page))
                                (remove #(= (last %) [:set :int]))
                                (remove #(= (last %) [:set :int]))
                                (map first)
                                (map first)
-                               set)
-      attrs-to-ignore #{:ast/version}]
-  (when-let [undeclared-attrs (seq (remove (some-fn malli-non-ref-attrs attrs-to-ignore) db-schema/db-non-ref-attributes))]
+                               set)]
+  (when-let [undeclared-attrs (seq (remove malli-non-ref-attrs db-schema/db-non-ref-attributes))]
     (throw (ex-info (str "The malli DB schema is missing the following non ref attributes from datascript's schema: "
     (throw (ex-info (str "The malli DB schema is missing the following non ref attributes from datascript's schema: "
                          (string/join ", " undeclared-attrs))
                          (string/join ", " undeclared-attrs))
                     {}))))
                     {}))))

+ 183 - 169
deps/db/src/logseq/db/frontend/property.cljs

@@ -1,169 +1,188 @@
 (ns logseq.db.frontend.property
 (ns logseq.db.frontend.property
   "Property related fns for DB graphs and frontend/datascript usage"
   "Property related fns for DB graphs and frontend/datascript usage"
-  (:require [clojure.set :as set]
-            [logseq.db.sqlite.util :as sqlite-util]
+  (:require [logseq.db.sqlite.util :as sqlite-util]
             [datascript.core :as d]
             [datascript.core :as d]
             [logseq.common.util :as common-util]
             [logseq.common.util :as common-util]
             [clojure.string :as string]))
             [clojure.string :as string]))
 
 
-;; FIXME: no support for built-in-extended-properties
-(def ^:large-vars/data-var built-in-properties
-  "Map of built in properties for db graphs. Each property has a config map with
-  the following keys:
-   * :schema - Property's schema. Required key
+(def ^:large-vars/data-var built-in-properties*
+  "Map of built in properties for db graphs with their :db/ident as keys.
+   Each property has a config map with the following keys:
+   * :schema - Property's schema. Required key. Has the following common keys:
+     * :type - Property type
+     * :cardinality - property cardinality. Default to one/single cardinality if not set
+     * :hide? - Boolean which hides property when set on a block
+     * :public? - Boolean which allows property to be used by user e.g. add and remove property to blocks/pages
+     * :view-context - Keyword to indicate which view contexts a property can be
+       seen in when :public? is set. Valid values are :page and :block. Property can
+       be viewed in any context if not set
    * :original-name - Property's :block/original-name
    * :original-name - Property's :block/original-name
+   * :name - Property's :block/name as a keyword. If none given, one is derived from the db/ident
    * :attribute - Property keyword that is saved to a datascript attribute outside of :block/properties
    * :attribute - Property keyword that is saved to a datascript attribute outside of :block/properties
-   * :visible - Boolean to indicate user can see and use this property"
-  {:alias {:original-name "Alias"
-           :attribute :block/alias
-           :db-ident :block/alias
-           :visible true
-           :schema {:type :page
-                    :cardinality :many}}
-   :tags {:original-name "Tags"
-          :attribute :block/tags
-          :db-ident :block/tags
-          :visible true
-          :schema {:type :page
-                   :cardinality :many
-                   :classes #{:logseq.class}}}
-   :pagetags {:original-name "pageTags"
-              :visible true
-              :schema {:type :page
-                       :cardinality :many}}
-   :background-color {:schema {:type :default :hide? true}}
-   :background-image {:schema {:type :default :hide? true}
-                      :visible true}
-   :heading {:schema {:type :any :hide? true}}      ; number (1-6) or boolean for auto heading
-   :created-from-block    {:schema {:db-attr-type :ref
-                                    :type :number}}
-   :created-from-property {:schema {:db-attr-type :ref
-                                    :type :number}}
-   :created-from-template {:schema {:db-attr-type :ref
-                                    :type :number}}
-   :source-page-id        {:schema {:type :ref}}
-   :built-in?             {:schema {:type :checkbox}}
-   :hide-properties?      {:schema {:type :checkbox}}
-   :query-table {:schema {:type :checkbox}}
+   * :closed-values - Vec of closed-value maps for properties with choices. Map
+     has keys :value, :db-ident, :uuid and :icon
+   * :db-ident - Keyword to set :db/ident and give property unique id in db"
+  {:block/alias           {:original-name "Alias"
+                           :attribute :block/alias
+                           :schema {:type :page
+                                    :cardinality :many
+                                    :view-context :page
+                                    :public? true}}
+   :block/tags           {:original-name "Tags"
+                          :attribute :block/tags
+                          :schema {:type :page
+                                   :cardinality :many
+                                   :public? true
+                                   :classes #{:logseq.class}}}
+   :logseq.property/page-tags {:original-name "pageTags"
+                               :schema {:type :page
+                                        :public? true
+                                        :view-context :page
+                                        :cardinality :many}}
+   :logseq.property/background-color {:schema {:type :default :hide? true}}
+   :logseq.property/background-image {:schema
+                                      {:type :default
+                                       :hide? true
+                                       :view-context :block
+                                       :public? true}}
+   ;; number (1-6) or boolean for auto heading
+   :logseq.property/heading {:schema {:type :any :hide? true}}
+   :logseq.property/created-from-block    {:schema {:type :uuid}}
+   :logseq.property/created-from-property {:schema {:type :uuid}}
+   :logseq.property/created-from-template {:schema {:type :uuid}}
+   :logseq.property/source-page-id        {:schema {:type :uuid}}
+   :logseq.property/built-in?             {:schema {:type :checkbox}}
+   :logseq.property/hide-properties?      {:schema {:type :checkbox}}
+   :logseq.property/query-table {:schema {:type :checkbox}}
    ;; query-properties is a coll of property uuids and keywords where keywords are special frontend keywords
    ;; query-properties is a coll of property uuids and keywords where keywords are special frontend keywords
-   :query-properties {:schema {:type :coll}}
+   :logseq.property/query-properties {:schema {:type :coll}}
    ;; query-sort-by is either a property uuid or a keyword where keyword is a special frontend keyword
    ;; query-sort-by is either a property uuid or a keyword where keyword is a special frontend keyword
-   :query-sort-by {:schema {:type :any}}
-   :query-sort-desc {:schema {:type :checkbox}}
-   :ls-type {:schema {:type :keyword}}
-   :hl-type {:schema {:type :keyword}}
-   :hl-page {:schema {:type :number}}
-   :hl-stamp {:schema {:type :number}}
-   :hl-color {:schema {:type :default}}
-   :logseq.macro-name {:schema {:type :default}}
-   :logseq.macro-arguments {:schema {:type :coll}}
-   :logseq.order-list-type {:schema {:type :default}}
-   :logseq.tldraw.page {:schema {:type :map}}
-   :logseq.tldraw.shape {:schema {:type :map}}
+   :logseq.property/query-sort-by {:schema {:type :any}}
+   :logseq.property/query-sort-desc {:schema {:type :checkbox}}
+   :logseq.property/ls-type {:schema {:type :keyword}}
+   :logseq.property/hl-type {:schema {:type :keyword}}
+   :logseq.property/hl-page {:schema {:type :number}}
+   :logseq.property/hl-stamp {:schema {:type :number}}
+   :logseq.property/hl-color {:schema {:type :default}}
+   :logseq.property/macro-name {:name :logseq.macro-name
+                                :schema {:type :default}}
+   :logseq.property/macro-arguments {:name :logseq.macro-arguments
+                                     :schema {:type :coll}}
+   :logseq.property/order-list-type {:name :logseq.order-list-type
+                                     :schema {:type :default}}
+   :logseq.property.tldraw/page {:name :logseq.tldraw.page
+                                 :schema {:type :map}}
+   :logseq.property.tldraw/shape {:name :logseq.tldraw.shape
+                                  :schema {:type :map}}
 
 
    ;; Task props
    ;; Task props
-   :status {:db-ident :logseq.property/status
-            :original-name "Status"
-            :schema
-            {:type :default}
-            :closed-values
-            (mapv (fn [[db-ident value icon]]
-                    {:db-ident db-ident
-                     :value value
-                     :uuid (random-uuid)
-                     :icon {:type :tabler-icon :id icon :name icon}})
-                  [[:logseq.property/status.backlog "Backlog" "Backlog"]
-                   [:logseq.property/status.todo "Todo" "Todo"]
-                   [:logseq.property/status.doing "Doing" "InProgress50"]
-                   [:logseq.property/status.in-review "In Review" "InReview"]
-                   [:logseq.property/status.done "Done" "Done"]
-                   [:logseq.property/status.canceled "Canceled" "Cancelled"]])
-            :visible true}
-   :priority {:db-ident :logseq.property/priority
-              :original-name "Priority"
-              :schema
-              {:type :default}
-              :closed-values
-              (mapv (fn [[db-ident value]]
-                      {:db-ident db-ident
-                       :value value
-                       :uuid (random-uuid)})
-                    [[:logseq.property/priority.urgent "Urgent"]
-                     [:logseq.property/priority.high "High"]
-                     [:logseq.property/priority.medium "Medium"]
-                     [:logseq.property/priority.low "Low"]])
-              :visible true}
-   :scheduled {:db-ident :logseq.property/scheduled
-               :original-name "Scheduled"
-               :schema {:db-attr-type :ref
-                        :type :date}
-               :visible true}
-   :deadline {:db-ident :logseq.property/deadline
-              :original-name "Deadline"
-              :schema {:db-attr-type :ref
-                       :type :date}
-              :visible true}
+   :logseq.task/status
+   {:original-name "Status"
+    :schema
+    {:type :default
+     :public? true}
+    :closed-values
+    (mapv (fn [[db-ident value icon]]
+            {:db-ident db-ident
+             :value value
+             :uuid (random-uuid)
+             :icon {:type :tabler-icon :id icon :name icon}})
+          [[:logseq.task/status.backlog "Backlog" "Backlog"]
+           [:logseq.task/status.todo "Todo" "Todo"]
+           [:logseq.task/status.doing "Doing" "InProgress50"]
+           [:logseq.task/status.in-review "In Review" "InReview"]
+           [:logseq.task/status.done "Done" "Done"]
+           [:logseq.task/status.canceled "Canceled" "Cancelled"]])}
+   :logseq.task/priority
+   {:original-name "Priority"
+    :schema
+    {:type :default
+     :public? true}
+    :closed-values
+    (mapv (fn [[db-ident value]]
+            {:db-ident db-ident
+             :value value
+             :uuid (random-uuid)})
+          [[:logseq.task/priority.urgent "Urgent"]
+           [:logseq.task/priority.high "High"]
+           [:logseq.task/priority.medium "Medium"]
+           [:logseq.task/priority.low "Low"]])}
+   :logseq.task/scheduled
+   {:original-name "Scheduled"
+    :schema {:type :date
+             :public? true}}
+   :logseq.task/deadline
+   {:original-name "Deadline"
+    :schema {:type :date
+             :public? true}}
 
 
    ;; TODO: Add more props :Assignee, :Estimate, :Cycle, :Project
    ;; TODO: Add more props :Assignee, :Estimate, :Cycle, :Project
 
 
    ;; color props
    ;; color props
-   :logseq.color {:schema
-                  {:type :default :hide? true}
-                  :closed-values
-                  (mapv #(hash-map :db-ident (keyword "logseq.property" (str "color." %))
-                                   :value %
-                                   :uuid (random-uuid))
-                        ;; Stringified version of frontend.colors/COLORS. Too basic to couple
-                        ["tomato" "red" "crimson" "pink" "plum" "purple" "violet" "indigo" "blue" "cyan" "teal" "green" "grass" "orange" "brown"])
-                  :visible true}
+   :logseq.property/color
+   {:name :logseq.color
+    :schema
+    {:type :default :hide? true :public? true}
+    :closed-values
+    (mapv #(hash-map :db-ident (keyword "logseq.property" (str "color." %))
+                     :value %
+                     :uuid (random-uuid))
+          ;; Stringified version of frontend.colors/COLORS. Too basic to couple
+          ["tomato" "red" "crimson" "pink" "plum" "purple" "violet" "indigo" "blue" "cyan" "teal" "green" "grass" "orange" "brown"])}
    ;; table-v2 props
    ;; table-v2 props
-   :logseq.table.version {:schema {:type :number :hide? true}
-                          :visible true}
-   :logseq.table.compact {:schema {:type :checkbox :hide? true}
-                          :visible true}
-   :logseq.table.headers {:schema
-                          {:type :default :hide? true}
-                          :closed-values
-                          (mapv #(hash-map :db-ident (keyword "logseq.property.table" (str "headers." %))
-                                           :value %
-                                           :uuid (random-uuid))
-                                ["uppercase" "capitalize" "capitalize-first" "lowercase"])
-                          :visible true}
-   :logseq.table.hover {:schema
-                        {:type :default :hide? true}
-                        :closed-values
-                        (mapv #(hash-map :db-ident (keyword "logseq.property.table" (str "hover." %))
-                                         :value %
-                                         :uuid (random-uuid))
-                              ["row" "col" "both" "none"])
-                        :visible true}
-   :logseq.table.borders {:schema {:type :checkbox :hide? true}
-                          :visible true}
-   :logseq.table.stripes {:schema {:type :checkbox :hide? true}
-                          :visible true}
-   :logseq.table.max-width {:schema {:type :number :hide? true}
-                            :visible true}
+   :logseq.property.table/version {:name :logseq.table.version
+                                   :schema {:type :number :hide? true :public? true :view-context :block}}
+   :logseq.property.table/compact {:name :logseq.table.compact
+                                   :schema {:type :checkbox :hide? true :public? true :view-context :block}}
+   :logseq.property.table/headers
+   {:name :logseq.table.headers
+    :schema
+    {:type :default :hide? true :public? true :view-context :block}
+    :closed-values
+    (mapv #(hash-map :db-ident (keyword "logseq.property.table" (str "headers." %))
+                     :value %
+                     :uuid (random-uuid))
+          ["uppercase" "capitalize" "capitalize-first" "lowercase"])}
+   :logseq.property.table/hover
+   {:name :logseq.table.hover
+    :schema
+    {:type :default :hide? true :public? true :view-context :block}
+    :closed-values
+    (mapv #(hash-map :db-ident (keyword "logseq.property.table" (str "hover." %))
+                     :value %
+                     :uuid (random-uuid))
+          ["row" "col" "both" "none"])}
+   :logseq.property.table/borders {:name :logseq.table.borders
+                                   :schema {:type :checkbox :hide? true :public? true :view-context :block}}
+   :logseq.property.table/stripes {:name :logseq.table.stripes
+                                   :schema {:type :checkbox :hide? true :public? true :view-context :block}}
+   :logseq.property.table/max-width {:name :logseq.table.max-width
+                                     :schema {:type :number :hide? true :public? true :view-context :block}}
 
 
-   :icon {:original-name "Icon"
-          :schema {:type :map}}
-   :public {:schema {:type :checkbox :hide? true}
-            :visible true}
-   :filters {:schema {:type :map}}
-   :exclude-from-graph-view {:schema {:type :checkbox :hide? true}
-                             :visible true}})
+   :logseq.property/icon {:original-name "Icon"
+                          :schema {:type :map}}
+   :logseq.property/public {:schema
+                            {:type :checkbox
+                             :hide? true
+                             :view-context :page
+                             :public? true}}
+   :logseq.property/filters {:schema {:type :map}}
+   :logseq.property/exclude-from-graph-view {:schema
+                                             {:type :checkbox
+                                              :hide? true
+                                              :view-context :page
+                                              :public? true}}})
 
 
-(def visible-built-in-properties
-  "These are built-in properties that users can see and use"
-  (set (keep (fn [[k v]] (when (:visible v) k)) built-in-properties)))
-
-(defonce built-in-properties-keys
-  (set (keys built-in-properties)))
-
-(def hidden-built-in-properties
-  (set/difference built-in-properties-keys visible-built-in-properties))
-
-(defonce built-in-properties-keys-str
-  (set (map name (keys built-in-properties))))
+(def built-in-properties
+  (->> built-in-properties*
+       (map (fn [[k v]]
+              (assert (and (keyword? k) (namespace k)))
+              [k
+               ;; All built-ins must have a :name
+               (if (:name v)
+                 v
+                 (assoc v :name (keyword (string/lower-case (name k)))))]))
+       (into {})))
 
 
 (defn valid-property-name?
 (defn valid-property-name?
   [s]
   [s]
@@ -171,25 +190,27 @@
   ;; Disallow tags or page refs as they would create unreferenceable page names
   ;; Disallow tags or page refs as they would create unreferenceable page names
   (not (re-find #"^(#|\[\[)" s)))
   (not (re-find #"^(#|\[\[)" s)))
 
 
+(defn get-pid
+  "Get a built-in property's id (keyword name for file graph and uuid for db graph)
+  given its db-ident. Use this fn on a file or db graph. Use
+  db-pu/get-built-in-property-uuid if only in a db graph context"
+  [repo db db-ident]
+  (if (sqlite-util/db-based-graph? repo)
+    db-ident
+    (get-in built-in-properties [db-ident :name])))
+
 (defn lookup
 (defn lookup
-  "Get the value of coll's (a map) `key`. For file and db graphs"
-  [repo db coll key]
-  (when db
-    (let [property-name (if (keyword? key)
-                          (name key)
-                          key)]
-      (if (sqlite-util/db-based-graph? repo)
-        (when-let [property (d/entity db [:block/name (common-util/page-name-sanity-lc property-name)])]
-          (get coll (:db/ident property)))
-        (get coll key)))))
+  "Get the value of coll by db-ident. For file and db graphs"
+  [repo db coll db-ident]
+  (get coll (get-pid repo db db-ident)))
 
 
 (defn get-block-property-value
 (defn get-block-property-value
-  "Get the value of block's property `key`"
-  [repo db block key]
+  "Get the value of built-in block's property by its db-ident"
+  [repo db block db-ident]
   (when db
   (when db
     (let [block (or (d/entity db (:db/id block)) block)]
     (let [block (or (d/entity db (:db/id block)) block)]
       (when-let [properties (:block/properties block)]
       (when-let [properties (:block/properties block)]
-        (lookup repo db properties key)))))
+        (lookup repo db properties db-ident)))))
 
 
 (defn name->db-ident
 (defn name->db-ident
   "Converts a built-in property's keyword name to its :db/ident equivalent.
   "Converts a built-in property's keyword name to its :db/ident equivalent.
@@ -201,19 +222,12 @@
     (keyword (str "logseq.property" additional-ns) prop-name)
     (keyword (str "logseq.property" additional-ns) prop-name)
     (keyword "logseq.property" (name legacy-name))))
     (keyword "logseq.property" (name legacy-name))))
 
 
-(defn get-pid
-  "Get a property's id (name or uuid) given its name. For file and db graphs"
-  [repo db property-name]
-  (if (sqlite-util/db-based-graph? repo)
-    (:block/uuid (d/entity db [:block/name (common-util/page-name-sanity-lc (name property-name))]))
-    property-name))
-
 (defn shape-block?
 (defn shape-block?
   [repo db block]
   [repo db block]
-  (= :whiteboard-shape (get-block-property-value repo db block :ls-type)))
+  (= :whiteboard-shape (get-block-property-value repo db block :logseq.property/ls-type)))
 
 
 (defn get-by-ident-or-name
 (defn get-by-ident-or-name
-  "Gets a property by ident or name"
+  "Gets a property by db-ident or name if it's a user property"
   [db ident-or-name]
   [db ident-or-name]
   (if (and (keyword? ident-or-name) (namespace ident-or-name))
   (if (and (keyword? ident-or-name) (namespace ident-or-name))
     (d/entity db ident-or-name)
     (d/entity db ident-or-name)

+ 7 - 0
deps/db/src/logseq/db/frontend/rules.cljc

@@ -11,6 +11,13 @@
       [?t :block/namespace ?p]
       [?t :block/namespace ?p]
       (namespace ?t ?c)]]
       (namespace ?t ?c)]]
 
 
+   :class-parent
+   '[[(class-parent ?p ?c)
+      [?c :class/parent ?p]]
+     [(class-parent ?p ?c)
+      [?t :class/parent ?p]
+      (class-parent ?t ?c)]]
+
    :alias
    :alias
    '[[(alias ?e2 ?e1)
    '[[(alias ?e2 ?e1)
       [?e2 :block/alias ?e1]]
       [?e2 :block/alias ?e1]]

+ 4 - 4
deps/db/src/logseq/db/frontend/schema.cljs

@@ -3,11 +3,9 @@
   (:require [clojure.set :as set]))
   (:require [clojure.set :as set]))
 
 
 (defonce version 2)
 (defonce version 2)
-(defonce ast-version 1)
 ;; A page is a special block, a page can corresponds to multiple files with the same ":block/name".
 ;; A page is a special block, a page can corresponds to multiple files with the same ":block/name".
 (def ^:large-vars/data-var schema
 (def ^:large-vars/data-var schema
   {:schema/version  {}
   {:schema/version  {}
-   :ast/version     {}
    :db/type         {}
    :db/type         {}
    :db/ident        {:db/unique :db.unique/identity}
    :db/ident        {:db/unique :db.unique/identity}
 
 
@@ -128,8 +126,10 @@
    (dissoc schema
    (dissoc schema
            :block/properties-text-values :block/pre-block? :recent/pages :file/handle :block/file
            :block/properties-text-values :block/pre-block? :recent/pages :file/handle :block/file
            :block/properties-order)
            :block/properties-order)
-   {:file/last-modified-at {}}
-   {:asset/uuid {:db/unique :db.unique/identity}
+   {:class/parent {:db/valueType :db.type/ref
+                   :db/index true}
+    :file/last-modified-at {}
+    :asset/uuid {:db/unique :db.unique/identity}
     :asset/meta {}}))
     :asset/meta {}}))
 
 
 (def retract-attributes
 (def retract-attributes

+ 2 - 2
deps/db/src/logseq/db/sqlite/common_db.cljs

@@ -156,11 +156,11 @@
   [db]
   [db]
   (let [schema (:schema db)
   (let [schema (:schema db)
         idents (remove nil?
         idents (remove nil?
-                       (let [e (d/entity db :graph/uuid)
+                       (let [e (d/entity db :logseq.kv/graph-uuid)
                              id (:graph/uuid e)]
                              id (:graph/uuid e)]
                          (when id
                          (when id
                            [{:db/id (:db/id e)
                            [{:db/id (:db/id e)
-                             :db/ident :graph/uuid
+                             :db/ident :logseq.kv/graph-uuid
                              :graph/uuid id}])))
                              :graph/uuid id}])))
         favorites (get-favorites db)
         favorites (get-favorites db)
         latest-journals (get-latest-journals db 3)
         latest-journals (get-latest-journals db 3)

+ 21 - 23
deps/db/src/logseq/db/sqlite/create_graph.cljs

@@ -15,15 +15,12 @@
   (let [built-in-properties (->>
   (let [built-in-properties (->>
                              (map (fn [[k v]]
                              (map (fn [[k v]]
                                     (assert (keyword? k))
                                     (assert (keyword? k))
-                                    [k (assoc v
-                                              :db-ident
-                                              (get v :db-ident (db-property/name->db-ident k)))])
+                                    [k v])
                                   db-property/built-in-properties)
                                   db-property/built-in-properties)
                              (into {}))]
                              (into {}))]
     (mapcat
     (mapcat
-     (fn [[k-keyword {:keys [schema original-name closed-values db-ident]}]]
-       (let [k-name (name k-keyword)
-             name (or original-name k-name)
+     (fn [[db-ident {:keys [schema original-name closed-values]}]]
+       (let [name (or original-name (name db-ident))
              blocks (if closed-values
              blocks (if closed-values
                       (db-property-util/build-closed-values
                       (db-property-util/build-closed-values
                        name
                        name
@@ -36,11 +33,12 @@
          (update blocks 0 default-db/mark-block-as-built-in)))
          (update blocks 0 default-db/mark-block-as-built-in)))
      built-in-properties)))
      built-in-properties)))
 
 
+
 (defn kv
 (defn kv
   "Creates a key-value pair tx with the key under the :db/ident namespace :logseq.kv.
   "Creates a key-value pair tx with the key under the :db/ident namespace :logseq.kv.
    For example, the :db/type key is stored under an entity with ident :logseq.kv.db/type"
    For example, the :db/type key is stored under an entity with ident :logseq.kv.db/type"
   [key value]
   [key value]
-  {:db/ident (keyword (str "logseq.kv." (namespace key)) (name key))
+  {:db/ident (keyword "logseq.kv" (str (namespace key) "-" (name key)))
    key value})
    key value})
 
 
 (defn build-db-initial-data
 (defn build-db-initial-data
@@ -66,23 +64,23 @@
                               (map :db/ident default-properties)
                               (map :db/ident default-properties)
                               default-properties)
                               default-properties)
         default-classes (map
         default-classes (map
-                         (fn [[k-keyword {:keys [schema original-name]}]]
-                           (let [db-ident (name k-keyword)]
+                         (fn [[db-ident {:keys [schema original-name]}]]
+                           (let [original-name' (or original-name (name db-ident))]
                              (default-db/mark-block-as-built-in
                              (default-db/mark-block-as-built-in
-                              (sqlite-util/build-new-class
-                               (let [properties (mapv
-                                                 (fn [db-ident]
-                                                   (let [property (get db-ident->properties db-ident)]
-                                                     (assert property (str "Built-in property " db-ident " is not defined yet"))
-                                                     db-ident))
-                                                 (:properties schema))]
-                                 (cond->
-                                  {:block/original-name (or original-name db-ident)
-                                   :block/name (common-util/page-name-sanity-lc db-ident)
-                                   :db/ident (keyword "logseq.class" db-ident)
-                                   :block/uuid (d/squuid)}
-                                   (seq properties)
-                                   (assoc :class/schema.properties properties)))))))
+                             (sqlite-util/build-new-class
+                              (let [properties (mapv
+                                                (fn [db-ident]
+                                                  (let [property (get db-ident->properties db-ident)]
+                                                    (assert property (str "Built-in property " db-ident " is not defined yet"))
+                                                    db-ident))
+                                                (:properties schema))]
+                                (cond->
+                                 {:block/original-name original-name'
+                                  :block/name (common-util/page-name-sanity-lc original-name')
+                                  :db/ident db-ident
+                                  :block/uuid (d/squuid)}
+                                  (seq properties)
+                                  (assoc :class/schema.properties properties)))))))
                          db-class/built-in-classes)
                          db-class/built-in-classes)
         db-idents (keep (fn [x] (when-let [ident (:db/ident x)]
         db-idents (keep (fn [x] (when-let [ident (:db/ident x)]
                                   {:db/ident ident}))
                                   {:db/ident ident}))

+ 4 - 3
deps/db/src/logseq/db/sqlite/db.cljs

@@ -89,9 +89,10 @@
   [graphs-dir db-name]
   [graphs-dir db-name]
   (let [[db-sanitized-name db-full-path] (get-db-full-path graphs-dir db-name)
   (let [[db-sanitized-name db-full-path] (get-db-full-path graphs-dir db-name)
         db (new sqlite db-full-path nil)
         db (new sqlite db-full-path nil)
-        schema (if (sqlite-util/db-based-graph? db-name)
-                 db-schema/schema-for-db-based-graph
-                 db-schema/schema)]
+        ;; For both desktop and CLI, only file graphs have db-name that indicate their db type
+        schema (if (sqlite-util/local-file-based-graph? db-name)
+                 db-schema/schema
+                 db-schema/schema-for-db-based-graph)]
     (sqlite-common-db/create-kvs-table! db)
     (sqlite-common-db/create-kvs-table! db)
     (swap! databases assoc db-sanitized-name db)
     (swap! databases assoc db-sanitized-name db)
     (let [storage (new-sqlite-storage db)
     (let [storage (new-sqlite-storage db)

+ 0 - 1
deps/db/test/logseq/db/sqlite/common_db_test.cljs

@@ -4,7 +4,6 @@
             ["path" :as node-path]
             ["path" :as node-path]
             [datascript.core :as d]
             [datascript.core :as d]
             [logseq.db.sqlite.common-db :as sqlite-common-db]
             [logseq.db.sqlite.common-db :as sqlite-common-db]
-            [logseq.db.frontend.schema :as db-schema]
             [logseq.common.util.date-time :as date-time-util]
             [logseq.common.util.date-time :as date-time-util]
             [logseq.db.sqlite.db :as sqlite-db]
             [logseq.db.sqlite.db :as sqlite-db]
             [clojure.string :as string]))
             [clojure.string :as string]))

+ 55 - 26
deps/db/test/logseq/db/sqlite/create_graph_test.cljs

@@ -4,9 +4,11 @@
             [clojure.set :as set]
             [clojure.set :as set]
             [datascript.core :as d]
             [datascript.core :as d]
             [logseq.db.frontend.schema :as db-schema]
             [logseq.db.frontend.schema :as db-schema]
-            [logseq.db.sqlite.create-graph :as sqlite-create-graph]))
+            [logseq.db.sqlite.create-graph :as sqlite-create-graph]
+            [logseq.db.frontend.validate :as db-validate]
+            [logseq.db :as ldb]))
 
 
-(deftest build-db-initial-data
+(deftest new-graph-db-idents
   (testing "a new graph follows :db/ident conventions for"
   (testing "a new graph follows :db/ident conventions for"
     (let [conn (d/create-conn db-schema/schema-for-db-based-graph)
     (let [conn (d/create-conn db-schema/schema-for-db-based-graph)
           _ (d/transact! conn (sqlite-create-graph/build-db-initial-data @conn "{}"))
           _ (d/transact! conn (sqlite-create-graph/build-db-initial-data @conn "{}"))
@@ -15,30 +17,57 @@
                                @conn)
                                @conn)
                           (map first))
                           (map first))
           default-idents (map :db/ident ident-ents)]
           default-idents (map :db/ident ident-ents)]
-     (testing "namespaces"
-       (is (= '() (remove namespace default-idents))
-           "All default :db/ident's have namespaces")
-       (is (= []
-              (->> (keep namespace default-idents)
-                   (remove #(string/starts-with? % "logseq."))))
-           "All default :db/ident namespaces start with logseq.")
-       (is (= #{"logseq.property" "logseq.class" "logseq.task" "logseq.kv"}
-              (->> (keep namespace default-idents)
-                   ;; only pull 1st and 2nd level namespaces e.g. logseq and logseq.property
-                   (keep #(re-find #"^([^.]+\.?([^.]+)?)" %))
-                   (map first)
-                   set))
-           "All default :db/ident's top-level namespaces are known"))
+      (is (> (count default-idents) 75)
+          "Approximate number of default idents is correct")
+
+      (testing "namespaces"
+        (is (= '() (remove namespace default-idents))
+            "All default :db/ident's have namespaces")
+        (is (= []
+               (->> (keep namespace default-idents)
+                    (remove #(string/starts-with? % "logseq."))))
+            "All default :db/ident namespaces start with logseq."))
 
 
       (testing "closed values"
       (testing "closed values"
         (let [closed-value-ents (filter #(string/includes? (name (:db/ident %)) ".") ident-ents)
         (let [closed-value-ents (filter #(string/includes? (name (:db/ident %)) ".") ident-ents)
-             closed-value-properties (->> closed-value-ents
-                                          (map :db/ident)
-                                          (map #(keyword (namespace %) (string/replace (name %) #".[^.]+$" "")))
-                                          set)]
-         (is (= []
-                (remove #(= ["closed value"] (:block/type %)) closed-value-ents))
-             "All property names that contain a '.' are closed values")
-         (is (= #{}
-                (set/difference closed-value-properties (set default-idents)))
-             "All closed values start with a prefix that is a property name"))))))
+              closed-value-properties (->> closed-value-ents
+                                           (map :db/ident)
+                                           (map #(keyword (namespace %) (string/replace (name %) #".[^.]+$" "")))
+                                           set)]
+          (is (= []
+                 (remove #(= ["closed value"] (:block/type %)) closed-value-ents))
+              "All property names that contain a '.' are closed values")
+          (is (= #{}
+                 (set/difference closed-value-properties (set default-idents)))
+              "All closed values start with a prefix that is a property name"))))))
+
+(deftest new-graph-marks-built-ins
+  (let [conn (d/create-conn db-schema/schema-for-db-based-graph)
+        _ (d/transact! conn (sqlite-create-graph/build-db-initial-data @conn "{}"))
+        idents (->> (d/q '[:find [(pull ?b [:db/ident :block/properties]) ...]
+                           :where [?b :db/ident]]
+                         @conn)
+                    ;; only kv's don't have built-in property
+                    (remove #(= "logseq.kv" (namespace (:db/ident %)))))]
+    (is (= []
+           (remove #(ldb/built-in? @conn %) idents))
+        "All entities with :db/ident have built-in property (except for kv idents)")))
+
+(deftest new-graph-creates-class
+  (let [conn (d/create-conn db-schema/schema-for-db-based-graph)
+        _ (d/transact! conn (sqlite-create-graph/build-db-initial-data @conn "{}"))
+        task (d/entity @conn :logseq.class/task)]
+    (is (contains? (:block/type task) "class")
+        "Task class has correct type")
+    (is (= 4 (count (get-in task [:block/schema :properties])))
+        "Has correct number of task properties")
+    (is (every? #(contains? (:block/type (d/entity @conn [:block/uuid %])) "property")
+                (get-in task [:schema :properties]))
+        "Each task property has correct type")))
+
+(deftest new-graph-is-valid
+  (let [conn (d/create-conn db-schema/schema-for-db-based-graph)
+        _ (d/transact! conn (sqlite-create-graph/build-db-initial-data @conn "{}"))
+        validation (db-validate/validate-db! @conn)]
+    (is (nil? (:errors validation))
+        "New graph has no validation errors")))

+ 20 - 10
deps/graph-parser/src/logseq/graph_parser/exporter.cljs

@@ -254,6 +254,14 @@
       (throw (ex-info (str "No uuid found for page " (pr-str k))
       (throw (ex-info (str "No uuid found for page " (pr-str k))
                       {:page k}))))
                       {:page k}))))
 
 
+(def built-in-property-names
+  "Set of all built-in property names as keywords. Using in-memory property
+  names because these are legacy names already in a user's file graph"
+  (->> db-property/built-in-properties
+       vals
+       (map :name)
+       set))
+
 (defn- update-properties
 (defn- update-properties
   "Updates block property names and values"
   "Updates block property names and values"
   [props db page-names-to-uuids
   [props db page-names-to-uuids
@@ -266,7 +274,7 @@
                                                 {:page k}))))
                                                 {:page k}))))
                           (fn prop-name->uuid [k]
                           (fn prop-name->uuid [k]
                             (cached-prop-name->uuid db page-names-to-uuids k)))
                             (cached-prop-name->uuid db page-names-to-uuids k)))
-        user-properties (apply dissoc props db-property/built-in-properties-keys)]
+        user-properties (apply dissoc props built-in-property-names)]
     (when (seq user-properties)
     (when (seq user-properties)
       (swap! (:block-properties-text-values import-state)
       (swap! (:block-properties-text-values import-state)
              assoc
              assoc
@@ -277,7 +285,7 @@
     (if (contains? props :template)
     (if (contains? props :template)
       {}
       {}
       (-> (update-built-in-property-values
       (-> (update-built-in-property-values
-           (select-keys props db-property/built-in-properties-keys)
+           (select-keys props built-in-property-names)
            db
            db
            (:ignored-properties import-state)
            (:ignored-properties import-state)
            (select-keys block [:block/name :block/content]))
            (select-keys block [:block/name :block/content]))
@@ -289,7 +297,9 @@
   ;; Already imported via a datascript attribute i.e. have :attribute on property config
   ;; Already imported via a datascript attribute i.e. have :attribute on property config
   [:tags :alias :collapsed
   [:tags :alias :collapsed
    ;; Not supported as they have been ignored for a long time and cause invalid built-in pages
    ;; Not supported as they have been ignored for a long time and cause invalid built-in pages
-   :now :later :doing :done :canceled :cancelled :in-progress :todo :wait :waiting])
+   :now :later :doing :done :canceled :cancelled :in-progress :todo :wait :waiting
+   ;; deprecated in db graphs
+   :macros :logseq.query/nlp-date])
 
 
 (defn- pre-update-properties
 (defn- pre-update-properties
   "Updates page and block properties before their property types are inferred"
   "Updates page and block properties before their property types are inferred"
@@ -302,7 +312,7 @@
                                property-classes)]
                                property-classes)]
     (->> (apply dissoc properties dissoced-props)
     (->> (apply dissoc properties dissoced-props)
          (keep (fn [[prop val]]
          (keep (fn [[prop val]]
-                 (if (not (contains? db-property/built-in-properties-keys prop))
+                 (if (not (contains? built-in-property-names prop))
                   ;; only update user properties
                   ;; only update user properties
                    (if (string? val)
                    (if (string? val)
                     ;; Ignore blank values as they were usually generated by templates
                     ;; Ignore blank values as they were usually generated by templates
@@ -330,7 +340,7 @@
               properties-to-infer (if (:template properties')
               properties-to-infer (if (:template properties')
                                     ;; Ignore template properties as they don't consistently have representative property values
                                     ;; Ignore template properties as they don't consistently have representative property values
                                     {}
                                     {}
-                                    (apply dissoc properties' db-property/built-in-properties-keys))
+                                    (apply dissoc properties' built-in-property-names))
               property-changes
               property-changes
               (->> properties-to-infer
               (->> properties-to-infer
                    (keep (fn [[prop val]]
                    (keep (fn [[prop val]]
@@ -562,7 +572,7 @@
     :tag-classes (set (map string/lower-case (:tag-classes user-options)))
     :tag-classes (set (map string/lower-case (:tag-classes user-options)))
     :property-classes (set/difference
     :property-classes (set/difference
                        (set (map (comp keyword string/lower-case) (:property-classes user-options)))
                        (set (map (comp keyword string/lower-case) (:property-classes user-options)))
-                       db-property/built-in-properties-keys)}))
+                       built-in-property-names)}))
 
 
 (defn add-file-to-db-graph
 (defn add-file-to-db-graph
   "Parse file and save parsed data to the given db graph. Options available:
   "Parse file and save parsed data to the given db graph. Options available:
@@ -737,7 +747,7 @@
                     [(get ?bp ?prop-uuid) ?_v]]
                     [(get ?bp ?prop-uuid) ?_v]]
                   @conn
                   @conn
                   (set (map :block/name user-classes)))
                   (set (map :block/name user-classes)))
-             (remove #(db-property/built-in-properties-keys-str (second %)))
+             (remove #(ldb/built-in? (d/entity @conn [:block/name (second %)])))
              (reduce (fn [acc [class-id _prop-name prop-uuid]]
              (reduce (fn [acc [class-id _prop-name prop-uuid]]
                        (update acc class-id (fnil conj #{}) prop-uuid))
                        (update acc class-id (fnil conj #{}) prop-uuid))
                      {}))
                      {}))
@@ -811,7 +821,7 @@
                        :filename-format (or (:file/name-format config) :legacy)
                        :filename-format (or (:file/name-format config) :legacy)
                        :verbose (:verbose options)}
                        :verbose (:verbose options)}
      :user-options (select-keys options [:tag-classes :property-classes])
      :user-options (select-keys options [:tag-classes :property-classes])
-     :page-tags-uuid (:block/uuid (d/entity @conn :logseq.property/pagetags))
+     :page-tags-uuid (:block/uuid (d/entity @conn :logseq.property/page-tags))
      :import-state (new-import-state)
      :import-state (new-import-state)
      :macros (or (:macros options) (:macros config))}
      :macros (or (:macros options) (:macros config))}
     (merge (select-keys options [:set-ui-state :export-file :notify-user]))))
     (merge (select-keys options [:set-ui-state :export-file :notify-user]))))
@@ -831,7 +841,7 @@
    * :<save-config-file - fn which saves a config file
    * :<save-config-file - fn which saves a config file
    * :<save-logseq-file - fn which saves a logseq file
    * :<save-logseq-file - fn which saves a logseq file
    * :<copy-asset - fn which copies asset file
    * :<copy-asset - fn which copies asset file
-   
+
    Note: See export-doc-files for additional options that are only for it"
    Note: See export-doc-files for additional options that are only for it"
   [repo-or-conn conn config-file *files {:keys [<read-file <copy-asset rpath-key log-fn]
   [repo-or-conn conn config-file *files {:keys [<read-file <copy-asset rpath-key log-fn]
                                  :or {rpath-key :path log-fn println}
                                  :or {rpath-key :path log-fn println}
@@ -858,4 +868,4 @@
        (export-favorites-from-config-edn conn repo-or-conn config {})
        (export-favorites-from-config-edn conn repo-or-conn config {})
        (export-class-properties conn repo-or-conn)
        (export-class-properties conn repo-or-conn)
        {:import-state (:import-state doc-options)
        {:import-state (:import-state doc-options)
-        :files files}))))
+        :files files}))))

+ 2 - 2
deps/graph-parser/src/logseq/graph_parser/whiteboard.cljs

@@ -88,8 +88,8 @@
            {:block/page default-page-ref})))
            {:block/page default-page-ref})))
 
 
 (defn shape->block [repo db shape page-name]
 (defn shape->block [repo db shape page-name]
-  (let [properties {(db-property/get-pid repo db :ls-type) :whiteboard-shape
-                    (db-property/get-pid repo db :logseq.tldraw.shape) shape}
+  (let [properties {(db-property/get-pid repo db :logseq.property/ls-type) :whiteboard-shape
+                    (db-property/get-pid repo db :logseq.property.tldraw/shape) shape}
         page-name (common-util/page-name-sanity-lc page-name)
         page-name (common-util/page-name-sanity-lc page-name)
         block {:block/uuid (if (uuid? (:id shape)) (:id shape) (uuid (:id shape)))
         block {:block/uuid (if (uuid? (:id shape)) (:id shape) (uuid (:id shape)))
                :block/page {:block/name page-name}
                :block/page {:block/name page-name}

+ 2 - 2
deps/outliner/src/logseq/outliner/core.cljs

@@ -641,8 +641,8 @@
   (let [db @conn
   (let [db @conn
         tb (when target-block (block db target-block))
         tb (when target-block (block db target-block))
         target-block (if sibling? target-block (when tb (:block (otree/-get-down tb conn))))
         target-block (if sibling? target-block (when tb (:block (otree/-get-down tb conn))))
-        list-type-fn (fn [block] (db-property/get-block-property-value repo db block :logseq.order-list-type))
-        k (db-property/get-pid repo db :logseq.order-list-type)]
+        list-type-fn (fn [block] (db-property/get-block-property-value repo db block :logseq.property/order-list-type))
+        k (db-property/get-pid repo db :logseq.property/order-list-type)]
     (if-let [list-type (and target-block (list-type-fn target-block))]
     (if-let [list-type (and target-block (list-type-fn target-block))]
       (mapv
       (mapv
        (fn [{:block/keys [content format] :as block}]
        (fn [{:block/keys [content format] :as block}]

+ 4 - 3
deps/shui/src/logseq/shui/dialog/core.cljs

@@ -122,9 +122,10 @@
                              (on-open-change {:value v :set-open! set-open!})
                              (on-open-change {:value v :set-open! set-open!})
                              (set-open! v))))}
                              (set-open! v))))}
       (dialog-content props
       (dialog-content props
-        (dialog-header
-          (when title (dialog-title title))
-          (when description (dialog-description description)))
+        (when title
+          (dialog-header
+            (when title (dialog-title title))
+            (when description (dialog-description description))))
         (when content
         (when content
           [:div.ui__dialog-main-content content])
           [:div.ui__dialog-main-content content])
         (when footer
         (when footer

+ 3 - 0
deps/shui/src/logseq/shui/popup/core.cljs

@@ -9,10 +9,13 @@
 (def popover (util/lsui-wrap "Popover"))
 (def popover (util/lsui-wrap "Popover"))
 (def popover-trigger (util/lsui-wrap "PopoverTrigger"))
 (def popover-trigger (util/lsui-wrap "PopoverTrigger"))
 (def popover-content (util/lsui-wrap "PopoverContent"))
 (def popover-content (util/lsui-wrap "PopoverContent"))
+(def popover-arrow (util/lsui-wrap "PopoverArrow"))
+(def popover-close (util/lsui-wrap "PopoverClose"))
 (def popover-remove-scroll (util/lsui-wrap "PopoverRemoveScroll"))
 (def popover-remove-scroll (util/lsui-wrap "PopoverRemoveScroll"))
 (def dropdown-menu (util/lsui-wrap "DropdownMenu"))
 (def dropdown-menu (util/lsui-wrap "DropdownMenu"))
 (def dropdown-menu-trigger (util/lsui-wrap "DropdownMenuTrigger"))
 (def dropdown-menu-trigger (util/lsui-wrap "DropdownMenuTrigger"))
 (def dropdown-menu-content (util/lsui-wrap "DropdownMenuContent"))
 (def dropdown-menu-content (util/lsui-wrap "DropdownMenuContent"))
+(def dropdown-menu-arrow (util/lsui-wrap "DropdownMenuArrow"))
 (def dropdown-menu-group (util/lsui-wrap "DropdownMenuGroup"))
 (def dropdown-menu-group (util/lsui-wrap "DropdownMenuGroup"))
 (def dropdown-menu-item (util/lsui-wrap "DropdownMenuItem"))
 (def dropdown-menu-item (util/lsui-wrap "DropdownMenuItem"))
 (def dropdown-menu-checkbox-item (util/lsui-wrap "DropdownMenuCheckboxItem"))
 (def dropdown-menu-checkbox-item (util/lsui-wrap "DropdownMenuCheckboxItem"))

+ 2 - 2
e2e-tests/utils.ts

@@ -140,12 +140,12 @@ export async function loadLocalGraph(page: Page, path: string): Promise<void> {
       await expect(sidebar).toHaveClass(/is-open/)
       await expect(sidebar).toHaveClass(/is-open/)
     }
     }
 
 
-    await page.click('#left-sidebar #repo-switch');
+    await page.click('#left-sidebar .repo-switch');
     await page.waitForSelector('#left-sidebar .dropdown-wrapper >> text="Add new graph"',
     await page.waitForSelector('#left-sidebar .dropdown-wrapper >> text="Add new graph"',
       { state: 'visible', timeout: 5000 })
       { state: 'visible', timeout: 5000 })
     await page.click('text=Add new graph')
     await page.click('text=Add new graph')
 
 
-    expect(page.locator('#repo-name')).toHaveText(pathlib.basename(path))
+    expect(page.locator('.repo-name')).toHaveText(pathlib.basename(path))
   }
   }
 
 
   setMockedOpenDirPath(page, ''); // reset it
   setMockedOpenDirPath(page, ''); // reset it

+ 1 - 2
package.json

@@ -9,7 +9,6 @@
         "@playwright/test": "=1.31.0",
         "@playwright/test": "=1.31.0",
         "@tailwindcss/aspect-ratio": "0.4.2",
         "@tailwindcss/aspect-ratio": "0.4.2",
         "@tailwindcss/forms": "0.5.3",
         "@tailwindcss/forms": "0.5.3",
-        "@tailwindcss/line-clamp": "0.4.2",
         "@tailwindcss/typography": "0.5.7",
         "@tailwindcss/typography": "0.5.7",
         "@types/gulp": "^4.0.7",
         "@types/gulp": "^4.0.7",
         "autoprefixer": "^10.4.13",
         "autoprefixer": "^10.4.13",
@@ -134,7 +133,7 @@
         "inter-ui": "^3.19.3",
         "inter-ui": "^3.19.3",
         "interactjs": "^1.10.17",
         "interactjs": "^1.10.17",
         "jszip": "3.8.0",
         "jszip": "3.8.0",
-        "katex": "^0.16.7",
+        "katex": "^0.16.10",
         "marked": "^5.1.2",
         "marked": "^5.1.2",
         "mldoc": "^1.5.8",
         "mldoc": "^1.5.8",
         "path": "0.12.7",
         "path": "0.12.7",

+ 3 - 0
packages/ui/@/components/ui/dropdown-menu.tsx

@@ -8,6 +8,8 @@ const DropdownMenu = DropdownMenuPrimitive.Root
 
 
 const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
 const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
 
 
+const DropdownMenuArrow = DropdownMenuPrimitive.Arrow
+
 const DropdownMenuGroup = DropdownMenuPrimitive.Group
 const DropdownMenuGroup = DropdownMenuPrimitive.Group
 
 
 const DropdownMenuPortal = DropdownMenuPrimitive.Portal
 const DropdownMenuPortal = DropdownMenuPrimitive.Portal
@@ -188,6 +190,7 @@ DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'
 export {
 export {
   DropdownMenu,
   DropdownMenu,
   DropdownMenuTrigger,
   DropdownMenuTrigger,
+  DropdownMenuArrow,
   DropdownMenuContent,
   DropdownMenuContent,
   DropdownMenuItem,
   DropdownMenuItem,
   DropdownMenuCheckboxItem,
   DropdownMenuCheckboxItem,

+ 3 - 1
packages/ui/@/components/ui/popover.tsx

@@ -11,6 +11,8 @@ const PopoverTrigger = PopoverPrimitive.Trigger
 
 
 const PopoverArrow = PopoverPrimitive.Arrow
 const PopoverArrow = PopoverPrimitive.Arrow
 
 
+const PopoverClose = PopoverPrimitive.Close
+
 const PopoverContent = React.forwardRef<
 const PopoverContent = React.forwardRef<
   React.ElementRef<typeof PopoverPrimitive.Content>,
   React.ElementRef<typeof PopoverPrimitive.Content>,
   React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
   React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
@@ -33,4 +35,4 @@ PopoverContent.displayName = PopoverPrimitive.Content.displayName
 
 
 const PopoverRemoveScroll = RemoveScroll
 const PopoverRemoveScroll = RemoveScroll
 
 
-export { Popover, PopoverTrigger, PopoverRemoveScroll, PopoverContent, PopoverArrow }
+export { Popover, PopoverTrigger, PopoverRemoveScroll, PopoverContent, PopoverArrow, PopoverClose }

+ 2 - 2
packages/ui/src/vars-classic.css

@@ -3,8 +3,8 @@
   --ls-tag-text-hover-opacity: 1;
   --ls-tag-text-hover-opacity: 1;
   --ls-page-text-size: 1em;
   --ls-page-text-size: 1em;
   --ls-page-title-size: 36px;
   --ls-page-title-size: 36px;
-  --ls-main-content-max-width: 810px;
-  --ls-main-content-max-width-wide: 1280px;
+  --ls-main-content-max-width: 960px;
+  --ls-main-content-max-width-wide: 1440px;
   --ls-font-family: Inter;
   --ls-font-family: Inter;
   --ls-scrollbar-width: 6px;
   --ls-scrollbar-width: 6px;
   --ls-border-radius-low: 4px;
   --ls-border-radius-low: 4px;

+ 2 - 1
resources/forge.config.js

@@ -20,9 +20,10 @@ module.exports = {
       'signature-flags': 'library'
       'signature-flags': 'library'
     },
     },
     osxNotarize: process.env['APPLE_ID'] ? {
     osxNotarize: process.env['APPLE_ID'] ? {
+      tool: 'notarytool',
       appleId: process.env['APPLE_ID'],
       appleId: process.env['APPLE_ID'],
       appleIdPassword: process.env['APPLE_ID_PASSWORD'],
       appleIdPassword: process.env['APPLE_ID_PASSWORD'],
-      ascProvider: process.env['APPLE_ASC_PROVIDER']
+      teamId: process.env['APPLE_TEAM_ID']
     } : undefined,
     } : undefined,
   },
   },
   makers: [
   makers: [

+ 6 - 6
resources/package.json

@@ -46,12 +46,12 @@
     "update-electron-app": "2.0.1"
     "update-electron-app": "2.0.1"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "@electron-forge/cli": "^6.0.4",
-    "@electron-forge/maker-deb": "^6.0.4",
-    "@electron-forge/maker-dmg": "^6.0.4",
-    "@electron-forge/maker-rpm": "^6.0.4",
-    "@electron-forge/maker-squirrel": "^6.0.4",
-    "@electron-forge/maker-zip": "^6.0.4",
+    "@electron-forge/cli": "^7.3.1",
+    "@electron-forge/maker-deb": "^7.3.1",
+    "@electron-forge/maker-dmg": "^7.3.1",
+    "@electron-forge/maker-rpm": "^7.3.1",
+    "@electron-forge/maker-squirrel": "^7.3.1",
+    "@electron-forge/maker-zip": "^7.3.1",
     "@electron/rebuild": "3.2.10",
     "@electron/rebuild": "3.2.10",
     "electron": "27.1.3",
     "electron": "27.1.3",
     "electron-builder": "^22.11.7",
     "electron-builder": "^22.11.7",

+ 1 - 1
scripts/src/logseq/tasks/db_graph/create_graph_with_properties.cljs

@@ -187,7 +187,7 @@
         blocks-tx (create-graph/create-blocks-tx
         blocks-tx (create-graph/create-blocks-tx
                    @conn
                    @conn
                    (create-init-data)
                    (create-init-data)
-                   {:property-uuids {:icon (:block/uuid (d/entity @conn [:block/name "icon"]))}})]
+                   {:property-uuids {:icon (:block/uuid (d/entity @conn :logseq.property/icon))}})]
     (println "Generating" (count (filter :block/name blocks-tx)) "pages and"
     (println "Generating" (count (filter :block/name blocks-tx)) "pages and"
              (count (filter :block/content blocks-tx)) "blocks ...")
              (count (filter :block/content blocks-tx)) "blocks ...")
     (d/transact! conn blocks-tx)
     (d/transact! conn blocks-tx)

+ 2 - 2
scripts/src/logseq/tasks/db_graph/create_graph_with_schema_org.cljs

@@ -75,7 +75,7 @@
                            (class-m "rdfs:comment")
                            (class-m "rdfs:comment")
                            (assoc :description (get-comment-string (class-m "rdfs:comment") renamed-pages)))}
                            (assoc :description (get-comment-string (class-m "rdfs:comment") renamed-pages)))}
       parent-class
       parent-class
-      (assoc :block/namespace {:db/id (get-class-db-id class-db-ids parent-class)})
+      (assoc :class/parent {:db/id (get-class-db-id class-db-ids parent-class)})
       (seq properties)
       (seq properties)
       (assoc :block/schema {:properties (mapv property-uuids properties)}))))
       (assoc :block/schema {:properties (mapv property-uuids properties)}))))
 
 
@@ -252,7 +252,7 @@
         pages (mapv #(hash-map :page
         pages (mapv #(hash-map :page
                                (->class-page % class-db-ids class-uuids class-to-properties property-uuids options))
                                (->class-page % class-db-ids class-uuids class-to-properties property-uuids options))
                     select-classes)]
                     select-classes)]
-    (assert (= ["Thing"] (keep #(when-not (:block/namespace (:page %))
+    (assert (= ["Thing"] (keep #(when-not (:class/parent (:page %))
                                   (:block/original-name (:page %)))
                                   (:block/original-name (:page %)))
                                pages))
                                pages))
             "Thing is the only class that doesn't have a parent class")
             "Thing is the only class that doesn't have a parent class")

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

@@ -31,6 +31,7 @@ body {
   line-height: 1.5;
   line-height: 1.5;
   min-height: 100%;
   min-height: 100%;
   word-break: break-word; /* compatible for overflow-wrap: anywhere */
   word-break: break-word; /* compatible for overflow-wrap: anywhere */
+  overflow-y: overlay;
 }
 }
 
 
 @layer base {
 @layer base {

+ 27 - 25
src/main/frontend/components/block.cljs

@@ -775,8 +775,8 @@
 
 
 (rum/defc page-reference < rum/reactive
 (rum/defc page-reference < rum/reactive
   "Component for page reference"
   "Component for page reference"
-  [html-export? s {:keys [nested-link? id] :as config} label]
-  (let [show-brackets? (state/show-brackets?)
+  [html-export? s {:keys [nested-link? show-brackets? id] :as config} label]
+  (let [show-brackets? (if (some? show-brackets?) show-brackets? (state/show-brackets?))
         block-uuid (:block/uuid config)
         block-uuid (:block/uuid config)
         contents-page? (= "contents" (string/lower-case (str id)))]
         contents-page? (= "contents" (string/lower-case (str id)))]
     (if (string/ends-with? s ".excalidraw")
     (if (string/ends-with? s ".excalidraw")
@@ -911,8 +911,8 @@
             db-id (:db/id block)
             db-id (:db/id block)
             block (when db-id (db/sub-block db-id))
             block (when db-id (db/sub-block db-id))
             properties (:block/properties block)
             properties (:block/properties block)
-            block-type (keyword (pu/lookup properties :ls-type))
-            hl-type (pu/lookup properties :hl-type)
+            block-type (keyword (pu/lookup properties :logseq.property/ls-type))
+            hl-type (pu/lookup properties :logseq.property/hl-type)
             repo (state/get-current-repo)
             repo (state/get-current-repo)
             stop-inner-events? (= block-type :whiteboard-shape)]
             stop-inner-events? (= block-type :whiteboard-shape)]
         (if (and block (:block/content block))
         (if (and block (:block/content block))
@@ -1424,16 +1424,18 @@
   [name config arguments]
   [name config arguments]
   (if-let [block-uuid (:block/uuid config)]
   (if-let [block-uuid (:block/uuid config)]
     (let [format (get-in config [:block :block/format] :markdown)
     (let [format (get-in config [:block :block/format] :markdown)
-          properties (-> (db/entity [:block/uuid block-uuid])
-                         (:block/page)
-                         (:db/id)
-                         (db/entity)
-                         :block/properties)
-          macros (pu/lookup properties :macros)
-          macro-content (or
-                         (get macros name)
-                         (get (state/get-macros) name)
-                         (get (state/get-macros) (keyword name)))
+          ;; :macros is deprecated for db graphs
+          macros-from-property (when (config/local-file-based-graph? (state/get-current-repo))
+                                 (-> (db/entity [:block/uuid block-uuid])
+                                     (:block/page)
+                                     (:db/id)
+                                     (db/entity)
+                                     :block/properties
+                                     :macros
+                                     (get name)))
+          macro-content (or macros-from-property
+                            (get (state/get-macros) name)
+                            (get (state/get-macros) (keyword name)))
           macro-content (cond
           macro-content (cond
                           (= (str name) "img")
                           (= (str name) "img")
                           (case (count arguments)
                           (case (count arguments)
@@ -1969,7 +1971,7 @@
         slide? (boolean (:slide? config))
         slide? (boolean (:slide? config))
         block-ref? (:block-ref? config)
         block-ref? (:block-ref? config)
         block-type (or (keyword
         block-type (or (keyword
-                        (pu/lookup properties :ls-type))
+                        (pu/lookup properties :logseq.property/ls-type))
                        :default)
                        :default)
         html-export? (:html-export? config)
         html-export? (:html-export? config)
         checkbox (when (and (not pre-block?)
         checkbox (when (and (not pre-block?)
@@ -1980,14 +1982,14 @@
                         (marker-switch t))
                         (marker-switch t))
         marker-cp (marker-cp t)
         marker-cp (marker-cp t)
         priority (priority-cp t)
         priority (priority-cp t)
-        bg-color (pu/lookup properties :background-color)
+        bg-color (pu/lookup properties :logseq.property/background-color)
         ;; `heading-level` is for backward compatibility, will remove it in later releases
         ;; `heading-level` is for backward compatibility, will remove it in later releases
         heading-level (:block/heading-level t)
         heading-level (:block/heading-level t)
         heading (or
         heading (or
                  (and heading-level
                  (and heading-level
                       (<= heading-level 6)
                       (<= heading-level 6)
                       heading-level)
                       heading-level)
-                 (pu/lookup properties :heading))
+                 (pu/lookup properties :logseq.property/heading))
         heading (if (true? heading) (min (inc level) 6) heading)
         heading (if (true? heading) (min (inc level) 6) heading)
         elem (if heading
         elem (if heading
                (keyword (str "h" heading
                (keyword (str "h" heading
@@ -1996,7 +1998,7 @@
     (->elem
     (->elem
      elem
      elem
      (merge
      (merge
-      {:data-hl-type (pu/lookup properties :hl-type)}
+      {:data-hl-type (pu/lookup properties :logseq.property/hl-type)}
       (when (and marker
       (when (and marker
                  (not (string/blank? marker))
                  (not (string/blank? marker))
                  (not= "nil" marker))
                  (not= "nil" marker))
@@ -2010,7 +2012,7 @@
            :class "px-1 with-bg-color"})))
            :class "px-1 with-bg-color"})))
 
 
      ;; children
      ;; children
-     (let [area?  (= :area (keyword (pu/lookup properties :hl-type)))
+     (let [area?  (= :area (keyword (pu/lookup properties :logseq.property/hl-type)))
            hl-ref #(when (and (or config/publishing? (util/electron?))
            hl-ref #(when (and (or config/publishing? (util/electron?))
                               (not (#{:default :whiteboard-shape} block-type)))
                               (not (#{:default :whiteboard-shape} block-type)))
                      [:div.prefix-link
                      [:div.prefix-link
@@ -2030,12 +2032,12 @@
 
 
                       [:span.hl-page
                       [:span.hl-page
                        [:strong.forbid-edit (str "P" (or
                        [:strong.forbid-edit (str "P" (or
-                                                      (pu/lookup properties :hl-page)
+                                                      (pu/lookup properties :logseq.property/hl-page)
                                                       "?"))]
                                                       "?"))]
                        [:label.blank " "]]
                        [:label.blank " "]]
 
 
                       (when (and area?
                       (when (and area?
-                                 (pu/lookup properties :hl-stamp))
+                                 (pu/lookup properties :logseq.property/hl-stamp))
                         (pdf-assets/area-display t))])]
                         (pdf-assets/area-display t))])]
        (remove-nils
        (remove-nils
         (concat
         (concat
@@ -2374,7 +2376,7 @@
         stop-events? (:stop-events? config)
         stop-events? (:stop-events? config)
         block-ref-with-title? (and block-ref? (not (state/show-full-blocks?)) (seq title))
         block-ref-with-title? (and block-ref? (not (state/show-full-blocks?)) (seq title))
         block-type (or
         block-type (or
-                    (pu/lookup properties :ls-type)
+                    (pu/lookup properties :logseq.property/ls-type)
                     :default)
                     :default)
         content (if (string? content) (string/trim content) "")
         content (if (string? content) (string/trim content) "")
         mouse-down-key (if (util/ios?)
         mouse-down-key (if (util/ios?)
@@ -2387,9 +2389,9 @@
                 :style {:width "100%" :pointer-events (when stop-events? "none")}}
                 :style {:width "100%" :pointer-events (when stop-events? "none")}}
 
 
                 (not (string/blank?
                 (not (string/blank?
-                      (pu/lookup properties :hl-color)))
+                      (pu/lookup properties :logseq.property/hl-color)))
                 (assoc :data-hl-color
                 (assoc :data-hl-color
-                       (pu/lookup properties :hl-color))
+                       (pu/lookup properties :logseq.property/hl-color))
 
 
                 (not block-ref?)
                 (not block-ref?)
                 (assoc mouse-down-key (fn [e]
                 (assoc mouse-down-key (fn [e]
@@ -3014,7 +3016,7 @@
         {:block/keys [uuid pre-block? content properties]} block
         {:block/keys [uuid pre-block? content properties]} block
         config (build-config config* block {:navigated? navigated? :navigating-block navigating-block})
         config (build-config config* block {:navigated? navigated? :navigating-block navigating-block})
         level (:level config)
         level (:level config)
-        heading? (pu/lookup properties :heading)
+        heading? (pu/lookup properties :logseq.property/heading)
         *control-show? (get container-state ::control-show?)
         *control-show? (get container-state ::control-show?)
         db-collapsed? (util/collapsed? block)
         db-collapsed? (util/collapsed? block)
         collapsed? (cond
         collapsed? (cond

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

@@ -45,7 +45,7 @@
            :updated-at
            :updated-at
            :block/updated-at
            :block/updated-at
 
 
-           (let [vals (map #(pu/lookup (:block/properties %) f) result)
+           (let [vals (map #(pu/lookup-by-name (:block/properties %) f) result)
                  int? (some integer? vals)
                  int? (some integer? vals)
                  repo (state/get-current-repo)
                  repo (state/get-current-repo)
                  prop-key (if (config/db-based-graph? repo)
                  prop-key (if (config/db-based-graph? repo)

+ 39 - 11
src/main/frontend/components/class.cljs

@@ -6,12 +6,13 @@
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.ui :as ui]
             [frontend.util :as util]
             [frontend.util :as util]
-            [rum.core :as rum]))
+            [rum.core :as rum]
+            [frontend.components.block :as block]))
 
 
 (rum/defc class-select
 (rum/defc class-select
   [page class on-select]
   [page class on-select]
   (let [repo (state/get-current-repo)
   (let [repo (state/get-current-repo)
-        children-pages (model/get-namespace-children repo (:db/id page))
+        children-pages (model/get-class-children repo (:db/id page))
         ;; Disallows cyclic hierarchies
         ;; Disallows cyclic hierarchies
         exclude-ids (-> (set (map (fn [id] (:block/uuid (db/entity id))) children-pages))
         exclude-ids (-> (set (map (fn [id] (:block/uuid (db/entity id))) children-pages))
                         (conj (:block/uuid page))) ; break cycle
                         (conj (:block/uuid page))) ; break cycle
@@ -53,9 +54,9 @@
                                       (if (seq value)
                                       (if (seq value)
                                         (db/transact!
                                         (db/transact!
                                          [{:db/id (:db/id page)
                                          [{:db/id (:db/id page)
-                                           :block/namespace [:block/uuid (uuid value)]}])
+                                           :class/parent [:block/uuid (uuid value)]}])
                                         (db/transact!
                                         (db/transact!
-                                         [[:db.fn/retractAttribute (:db/id page) :block/namespace]]))))]
+                                          [[:db.fn/retractAttribute (:db/id page) :class/parent]]))))]
       [:div.opacity-50.pointer.text-sm.cursor-pointer {:on-click #(reset! *show? true)}
       [:div.opacity-50.pointer.text-sm.cursor-pointer {:on-click #(reset! *show? true)}
        "Empty"])))
        "Empty"])))
 
 
@@ -73,22 +74,22 @@
         [:div.col-span-2 "Parent class:"]
         [:div.col-span-2 "Parent class:"]
         (if config/publishing?
         (if config/publishing?
           [:div.col-span-3
           [:div.col-span-3
-           (if-let [parent-class (some-> (:db/id (:block/namespace page))
+           (if-let [parent-class (some-> (:db/id (:class/parent page))
                                          db/entity
                                          db/entity
                                          :block/original-name)]
                                          :block/original-name)]
              [:a {:on-click #(route-handler/redirect-to-page! parent-class)}
              [:a {:on-click #(route-handler/redirect-to-page! parent-class)}
               parent-class]
               parent-class]
              "None")]
              "None")]
           [:div.col-span-3
           [:div.col-span-3
-           (let [parent (some-> (:db/id (:block/namespace page))
+           (let [parent (some-> (:db/id (:class/parent page))
                                 db/entity)]
                                 db/entity)]
              (page-parent page parent))])]
              (page-parent page parent))])]
 
 
-       (when (:block/namespace page)
-         (let [ancestor-pages (loop [namespaces [page]]
-                                (if-let [parent (:block/namespace (last namespaces))]
-                                  (recur (conj namespaces parent))
-                                  namespaces))
+       (when (:class/parent page)
+         (let [ancestor-pages (loop [parents [page]]
+                                (if-let [parent (:class/parent (last parents))]
+                                  (recur (conj parents parent))
+                                  parents))
                class-ancestors (map :block/original-name (reverse ancestor-pages))]
                class-ancestors (map :block/original-name (reverse ancestor-pages))]
            (when (> (count class-ancestors) 2)
            (when (> (count class-ancestors) 2)
              [:div.grid.grid-cols-5.gap-1.items-center.class-ancestors
              [:div.grid.grid-cols-5.gap-1.items-center.class-ancestors
@@ -100,3 +101,30 @@
                                    [:span class-name]
                                    [:span class-name]
                                    [:a {:on-click #(route-handler/redirect-to-page! class-name)} class-name]))
                                    [:a {:on-click #(route-handler/redirect-to-page! class-name)} class-name]))
                                class-ancestors))]])))])))
                                class-ancestors))]])))])))
+
+(defn class-children-aux
+  [class {:keys [default-collapsed?] :as opts}]
+  (let [children (:class/_parent class)]
+    (when (seq children)
+      [:ul
+       (for [child (sort-by :block/original-name children)]
+         (let [title [:li.ml-2 (block/page-reference false (:block/original-name child) {:show-brackets? false} nil)]]
+           (if (seq (:class/_parent child))
+             (ui/foldable
+              title
+              (class-children-aux child opts)
+              {:default-collapsed? default-collapsed?})
+             title)))])))
+
+(rum/defc class-children
+  [class]
+  (when (seq (:class/_parent class))
+    (let [children-pages (model/get-class-children (state/get-current-repo) (:db/id class))
+          ;; Expand children if there are about a pageful of total blocks to display
+          default-collapsed? (> (count children-pages) 30)]
+      [:div.mt-4
+       (ui/foldable
+        [:h2.font-medium "Child classes (" (count children-pages) ")"]
+        [:div.mt-2.ml-1 (class-children-aux class {:default-collapsed? default-collapsed?})]
+        {:default-collapsed? false
+         :title-trigger? true})])))

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

@@ -367,7 +367,7 @@
         {:aria-label "Navigation menu"}
         {:aria-label "Navigation menu"}
         (repo/repos-dropdown)
         (repo/repos-dropdown)
 
 
-        [:div.nav-header.flex.flex-col.mt-2
+        [:div.nav-header.flex.flex-col.mt-1
          (let [page (:page default-home)]
          (let [page (:page default-home)]
            (if (and page (not (state/enable-journals? (state/get-current-repo))))
            (if (and page (not (state/enable-journals? (state/get-current-repo))))
              (sidebar-item
              (sidebar-item
@@ -955,7 +955,7 @@
       [:button#skip-to-main
       [:button#skip-to-main
        {:on-click #(ui/focus-element (ui/main-node))
        {:on-click #(ui/focus-element (ui/main-node))
         :on-key-up (fn [e]
         :on-key-up (fn [e]
-                     (when (= (.-key e) "Enter")
+                     (when (= "Enter" (.-key e))
                        (ui/focus-element (ui/main-node))))}
                        (ui/focus-element (ui/main-node))))}
        (t :accessibility/skip-to-main-content)]
        (t :accessibility/skip-to-main-content)]
       [:div.#app-container
       [:div.#app-container

+ 6 - 2
src/main/frontend/components/container.css

@@ -534,7 +534,7 @@
   @apply w-auto md:max-w-4xl overflow-hidden;
   @apply w-auto md:max-w-4xl overflow-hidden;
 
 
   .settings-modal {
   .settings-modal {
-    @apply -mx-6 -mt-10 -mb-6 rounded-xl;
+    @apply -mx-6 -mt-6 -mb-6 rounded-xl;
   }
   }
 }
 }
 
 
@@ -542,6 +542,10 @@
   width: 100%;
   width: 100%;
   max-width: var(--ls-main-content-max-width);
   max-width: var(--ls-main-content-max-width);
   flex: 1;
   flex: 1;
+
+  .page {
+    @apply px-6;
+  }
 }
 }
 
 
 .cp__sidebar-help {
 .cp__sidebar-help {
@@ -774,7 +778,7 @@
 
 
 /* Workaround for Linux Intel GPU text rendering issue GH#7233 */
 /* Workaround for Linux Intel GPU text rendering issue GH#7233 */
 .is-electron.is-linux .cp__menubar-repos {
 .is-electron.is-linux .cp__menubar-repos {
-  #repo-switch, .nav-header .flex-1 {
+  .repo-switch, .nav-header .flex-1 {
     position: relative;
     position: relative;
   }
   }
 }
 }

+ 1 - 1
src/main/frontend/components/content.cljs

@@ -186,7 +186,7 @@
         db? (config/db-based-graph? repo)]
         db? (config/db-based-graph? repo)]
     (when-let [block (db/entity [:block/uuid block-id])]
     (when-let [block (db/entity [:block/uuid block-id])]
       (let [properties (:block/properties block)
       (let [properties (:block/properties block)
-            heading (or (pu/lookup properties :heading)
+            heading (or (pu/lookup properties :logseq.property/heading)
                         false)]
                         false)]
         [:.menu-links-wrapper
         [:.menu-links-wrapper
          (ui/menu-background-color #(property-handler/set-block-property! repo block-id :logseq.property/background-color %)
          (ui/menu-background-color #(property-handler/set-block-property! repo block-id :logseq.property/background-color %)

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

@@ -584,7 +584,7 @@
   [block content format]
   [block content format]
   (let [content (if content (str content) "")
   (let [content (if content (str content) "")
         properties (:block/properties block)
         properties (:block/properties block)
-        heading (pu/lookup properties :heading)
+        heading (pu/lookup properties :logseq.property/heading)
         heading (if (true? heading)
         heading (if (true? heading)
                   (min (inc (:block/level block)) 6)
                   (min (inc (:block/level block)) 6)
                   heading)]
                   heading)]

+ 85 - 61
src/main/frontend/components/header.cljs

@@ -130,70 +130,94 @@
          "platform="
          "platform="
          (js/encodeURIComponent platform))))
          (js/encodeURIComponent platform))))
 
 
-(rum/defc dropdown-menu < rum/reactive
-  < {:key-fn #(identity "repos-dropdown-menu")}
+(rum/defc toolbar-dots-menu < rum/reactive
   [{:keys [current-repo t]}]
   [{:keys [current-repo t]}]
   (let [page-menu (page-menu/page-menu nil)
   (let [page-menu (page-menu/page-menu nil)
         page-menu-and-hr (when (seq page-menu)
         page-menu-and-hr (when (seq page-menu)
                            (concat page-menu [{:hr true}]))
                            (concat page-menu [{:hr true}]))
-        login? (and (state/sub :auth/id-token) (user-handler/logged-in?))]
-    (ui/dropdown-with-links
-     (fn [{:keys [toggle-fn]}]
-       [:button.button.icon.toolbar-dots-btn
-        {:on-click toggle-fn
-         :title (t :header/more)}
-        (ui/icon "dots" {:size ui/icon-size})])
-     (->>
-      [(when (state/enable-editing?)
-         {:title (t :settings)
-          :options {:on-click state/open-settings!}
-          :icon (ui/icon "settings")})
-
-       (when config/lsp-enabled?
-         {:title (t :plugins)
-          :options {:on-click #(plugin-handler/goto-plugins-dashboard!)}
-          :icon (ui/icon "apps")})
-
-       (when config/lsp-enabled?
-         {:title (t :themes)
-          :options {:on-click #(plugins/open-select-theme!)}
-          :icon (ui/icon "palette")})
-
-       (when current-repo
-         {:title (t :export-graph)
-          :options {:on-click #(shui/dialog-open! export/export)}
-          :icon (ui/icon "database-export")})
-
-       (when (and current-repo (state/enable-editing?))
-         {:title (t :import)
-          :options {:href (rfe/href :import)}
-          :icon (ui/icon "file-upload")})
-
-       (when-not config/publishing?
-         {:title [:div.flex-row.flex.justify-between.items-center
-                  [:span (t :join-community)]]
-          :options {:href "https://discuss.logseq.com"
-                    :title (t :discourse-title)
-                    :target "_blank"}
-          :icon (ui/icon "brand-discord")})
-
-       (when config/publishing?
-         {:title (t :toggle-theme)
-          :options {:on-click #(state/toggle-theme!)}
-          :icon (ui/icon "bulb")})
-
-       (when login? {:hr true})
-       (when login?
-         {:item [:span.flex.flex-col.relative.group.pt-1
-                 [:b.leading-none (user-handler/username)]
-                 [:small.opacity-70 (user-handler/email)]
-                 [:i.absolute.opacity-0.group-hover:opacity-100.text-red-rx-09
-                  {:class "right-1 top-3" :title (t :logout)}
-                  (ui/icon "logout")]]
-          :options {:on-click #(user-handler/logout)}})]
-       (concat page-menu-and-hr)
-       (remove nil?))
-      {})))
+        login? (and (state/sub :auth/id-token) (user-handler/logged-in?))
+        items (fn []
+                (->>
+                  [(when (state/enable-editing?)
+                     {:title (t :settings)
+                      :options {:on-click state/open-settings!}
+                      :icon (ui/icon "settings")})
+
+                   (when config/lsp-enabled?
+                     {:title (t :plugins)
+                      :options {:on-click #(plugin-handler/goto-plugins-dashboard!)}
+                      :icon (ui/icon "apps")})
+
+                   (when config/lsp-enabled?
+                     {:title (t :themes)
+                      :options {:on-click #(plugins/open-select-theme!)}
+                      :icon (ui/icon "palette")})
+
+                   (when current-repo
+                     {:title (t :export-graph)
+                      :options {:on-click #(shui/dialog-open! export/export)}
+                      :icon (ui/icon "database-export")})
+
+                   (when (and current-repo (state/enable-editing?))
+                     {:title (t :import)
+                      :options {:href (rfe/href :import)}
+                      :icon (ui/icon "file-upload")})
+
+                   (when-not config/publishing?
+                     {:title [:div.flex-row.flex.justify-between.items-center
+                              [:span (t :join-community)]]
+                      :options {:href "https://discuss.logseq.com"
+                                :title (t :discourse-title)
+                                :target "_blank"}
+                      :icon (ui/icon "brand-discord")})
+
+                   (when config/publishing?
+                     {:title (t :toggle-theme)
+                      :options {:on-click #(state/toggle-theme!)}
+                      :icon (ui/icon "bulb")})
+
+                   (when login? {:hr true})
+                   (when login?
+                     {:item [:span.flex.flex-col.relative.group.pt-1.w-full
+                             [:b.leading-none (user-handler/username)]
+                             [:small.opacity-70 (user-handler/email)]
+                             [:i.absolute.opacity-0.group-hover:opacity-100.text-red-rx-09
+                              {:class "right-1 top-3" :title (t :logout)}
+                              (ui/icon "logout")]]
+                      :options {:on-click #(user-handler/logout)
+                                :class "w-full"}})]
+                  (concat page-menu-and-hr)
+                  (remove nil?)))]
+    [:button.button.icon.toolbar-dots-btn
+     {:title (t :header/more)
+      :on-click (fn [^js e]
+                  (shui/popup-show! (.-target e)
+                    (fn [{:keys [id]}]
+                      (for [{:keys [hr item title options icon]} (items)]
+                        (let [on-click' (:on-click options)
+                              href (:href options)]
+                          (if hr
+                            (shui/dropdown-menu-separator)
+                            (shui/dropdown-menu-item
+                             (assoc options
+                                    :on-click (fn [^js e]
+                                                (when on-click'
+                                                  (when-not (false? (on-click' e))
+                                                    (shui/popup-hide! id)))))
+                             (or item
+                                 (if href
+                                   [:a.flex.items-center.w-full
+                                    {:href href :on-click #(shui/popup-hide! id)
+                                     :style {:color "inherit"}}
+                                    [:span.flex.items-center.gap-1.w-full
+                                     icon [:div title]]]
+                                   [:span.flex.items-center.gap-1.w-full
+                                    icon [:div title]])))))))
+                    {:align "end"
+                     :as-dropdown? true
+                     :content-props {:class "w-64"
+                                     :align-offset -32}}))}
+     (ui/icon "dots" {:size ui/icon-size})]))
 
 
 (rum/defc back-and-forward
 (rum/defc back-and-forward
   < {:key-fn #(identity "nav-history-buttons")}
   < {:key-fn #(identity "nav-history-buttons")}
@@ -333,7 +357,7 @@
         [:a.text-sm.font-medium.button {:href (rfe/href :graph)}
         [:a.text-sm.font-medium.button {:href (rfe/href :graph)}
          (t :graph)])
          (t :graph)])
 
 
-      (dropdown-menu {:t            t
+      (toolbar-dots-menu {:t            t
                       :current-repo current-repo
                       :current-repo current-repo
                       :default-home default-home})
                       :default-home default-home})
 
 

+ 0 - 5
src/main/frontend/components/header.css

@@ -172,11 +172,6 @@
   transform: scale(0.9);
   transform: scale(0.9);
 }
 }
 
 
-#repo-name {
-  @apply inline-flex items-center whitespace-nowrap;
-  max-width: 16ch;
-}
-
 .button {
 .button {
   @apply h-8 px-2.5 py-1 rounded-md opacity-90 block select-none hover:opacity-100 active:opacity-80;
   @apply h-8 px-2.5 py-1 rounded-md opacity-90 block select-none hover:opacity-100 active:opacity-80;
 
 

+ 20 - 58
src/main/frontend/components/hierarchy.cljs

@@ -8,8 +8,7 @@
             [frontend.ui :as ui]
             [frontend.ui :as ui]
             [medley.core :as medley]
             [medley.core :as medley]
             [rum.core :as rum]
             [rum.core :as rum]
-            [frontend.util :as util]
-            [frontend.config :as config]))
+            [frontend.util :as util]))
 
 
 (defn- get-relation
 (defn- get-relation
   "Get all parent pages along the namespace hierarchy path.
   "Get all parent pages along the namespace hierarchy path.
@@ -44,62 +43,25 @@
             :else
             :else
             nil))))))
             nil))))))
 
 
-(rum/defc page-children
-  [page-id parent-children-map namespace-page-map options]
-  [:.ml-4.mb-2
-   {:key (str "page-children-" page-id)}
-   (->> (parent-children-map page-id)
-        (sort-by #(get-in namespace-page-map [% :block/original-name]))
-        (map #(let [child-name (get-in namespace-page-map [% :block/original-name])]
-                (if (seq (parent-children-map %))
-                  (ui/foldable (block/page-reference false child-name {} child-name)
-                               (page-children % parent-children-map namespace-page-map options)
-                               (select-keys options [:default-collapsed?]))
-                  [:div
-                   (block/page-reference false child-name {} child-name)]))))])
-
-(rum/defc db-version-hierarchy
-  [page namespace-pages]
-  (let [parent-children-map (reduce (fn [acc m]
-                                      (update acc
-                                              (get-in m [:block/namespace :db/id])
-                                              (fnil conj [])
-                                              (:db/id m)))
-                                    {}
-                                    namespace-pages)
-        namespace-page-map (into {} (map (juxt :db/id identity) namespace-pages))
-        page-id (:db/id (db/entity [:block/name (util/page-name-sanity-lc page)]))
-        ;; Expand children if there are about a page-ful of total blocks to display
-        default-collapsed? (> (count namespace-pages) 30)]
-    [:div.page-hierarchy.mt-6
-     (ui/foldable
-      [:h2.font-bold.opacity-30 (str "Hierarchy (" (count namespace-pages) ")")]
-      [:div.p-4
-       (page-children page-id parent-children-map namespace-page-map {:default-collapsed? default-collapsed?})]
-      {:default-collapsed? false
-       :title-trigger? true})]))
-
 (rum/defc structures
 (rum/defc structures
   [page]
   [page]
-  (let [{:keys [namespaces namespace-pages]} (get-relation page)]
+  (let [{:keys [namespaces]} (get-relation page)]
     (when (seq namespaces)
     (when (seq namespaces)
-      (if (config/db-based-graph? (state/get-current-repo))
-        (db-version-hierarchy page namespace-pages)
-        [:div.page-hierarchy.mt-6
-         (ui/foldable
-          [:h2.font-bold.opacity-30 "Hierarchy"]
-          [:ul.namespaces {:style {:margin "12px 24px"}}
-           (for [namespace namespaces]
-             [:li.my-2
-              (->>
-               (for [[idx page] (medley/indexed namespace)]
-                 (when (and (string? page) page)
-                   (let [full-page (->> (take (inc idx) namespace)
-                                        util/string-join-path)]
-                     (block/page-reference false
-                                           full-page
-                                           {}
-                                           page))))
-               (interpose [:span.mx-2.opacity-30 "/"]))])]
-          {:default-collapsed? false
-           :title-trigger? true})]))))
+      [:div.page-hierarchy.mt-6
+       (ui/foldable
+        [:h2.font-bold.opacity-30 "Hierarchy"]
+        [:ul.namespaces {:style {:margin "12px 24px"}}
+         (for [namespace namespaces]
+           [:li.my-2
+            (->>
+             (for [[idx page] (medley/indexed namespace)]
+               (when (and (string? page) page)
+                 (let [full-page (->> (take (inc idx) namespace)
+                                      util/string-join-path)]
+                   (block/page-reference false
+                                         full-page
+                                         {}
+                                         page))))
+             (interpose [:span.mx-2.opacity-30 "/"]))])]
+        {:default-collapsed? false
+         :title-trigger? true})])))

+ 2 - 8
src/main/frontend/components/journal.css

@@ -6,16 +6,10 @@
   }
   }
 
 
   .journal-item {
   .journal-item {
-    border-top: 1px solid;
-    border-top-color: var(--lx-gray-07, var(--ls-border-color, var(--rx-gray-06)));
-    margin: 24px 0;
-    padding: 24px 0;
-    min-height: 250px;
+    @apply border-t min-h-[250px];
 
 
     &:first-child {
     &:first-child {
-      padding-top: 0;
-      border-top: none;
-      min-height: 500px;
+      @apply pt-0 border-none min-h-[500px];
     }
     }
   }
   }
 }
 }

+ 55 - 12
src/main/frontend/components/page.css

@@ -229,13 +229,10 @@
 }
 }
 
 
 .ls-page-title {
 .ls-page-title {
-  @apply rounded-sm;
-
-  padding: 5px 8px 10px 8px;
-  margin: 0 -6px;
+  @apply rounded-sm -mx-1.5 px-2 pt-1.5;
 
 
   &.title {
   &.title {
-    margin-bottom: 12px;
+    @apply mb-3;
   }
   }
 
 
   .edit-input {
   .edit-input {
@@ -318,8 +315,24 @@ html.is-native-iphone-without-notch {
   }
   }
 }
 }
 
 
-.cp__right-sidebar .add-button-link {
-  margin-left: 21px;
+.cp__right-sidebar  {
+  .add-button-link {
+    margin-left: 21px;
+  }
+
+  .page-info {
+    @apply mx-2;
+
+    .ls-page-properties {}
+
+    &.is-collapsed {
+      @apply !py-0 -mb-1.5;
+
+      &:not(:has(.select-item)) {
+        @apply hidden;
+      }
+    }
+  }
 }
 }
 
 
 html.is-native-android,
 html.is-native-android,
@@ -388,9 +401,43 @@ html.is-native-ios {
 }
 }
 
 
 .page-info {
 .page-info {
-  @apply min-h-[46px] ml-[-15px] mt-[-6px];
+  @apply ml-[-10px] mb-[12px] border rounded-md;
+
+  &-inner {
+    @apply py-2;
+  }
+
+  .ls-page-properties {
+    @apply bg-gray-03 rounded-md px-3 gap-1;
+  }
+
+  .configure-wrap {
+    @apply px-2;
+  }
+
+  .ls-new-property {
+    @apply mt-1;
+  }
 
 
   &.is-collapsed {
   &.is-collapsed {
+    @apply border-transparent mt-[-4px] -mb-[14px];
+
+    &:has(.select-item) {
+      @apply py-2 relative -left-1;
+
+      .info-title {
+        @apply relative -top-1;
+      }
+    }
+
+    .page-info-inner {
+      @apply py-0 relative -top-1.5 min-h-[26px];
+
+      &:has(.ls-page-properties) {
+        @apply mb-3 opacity-90;
+      }
+    }
+
     .ls-new-property {
     .ls-new-property {
       @apply hidden;
       @apply hidden;
     }
     }
@@ -407,10 +454,6 @@ html.is-native-ios {
   }
   }
 }
 }
 
 
-.sidebar-item .page-info {
-  margin: 0 8px;
-}
-
 .page-info-title-placeholder {
 .page-info-title-placeholder {
   min-height: 28px;
   min-height: 28px;
 }
 }

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

@@ -18,8 +18,7 @@
             [frontend.config :as config]
             [frontend.config :as config]
             [frontend.handler.user :as user-handler]
             [frontend.handler.user :as user-handler]
             [frontend.handler.file-sync :as file-sync-handler]
             [frontend.handler.file-sync :as file-sync-handler]
-            [logseq.common.path :as path]
-            [frontend.handler.property.util :as pu]))
+            [logseq.common.path :as path]))
 
 
 (defn- delete-page!
 (defn- delete-page!
   [page-name]
   [page-name]
@@ -57,7 +56,7 @@
           whiteboard? (contains? (set (:block/type page)) "whiteboard")
           whiteboard? (contains? (set (:block/type page)) "whiteboard")
           block? (and page (util/uuid-string? page-name) (not whiteboard?))
           block? (and page (util/uuid-string? page-name) (not whiteboard?))
           contents? (= page-name "contents")
           contents? (= page-name "contents")
-          public? (true? (pu/lookup (:block/properties page) :public))
+          public? (:logseq.property/public page)
           _favorites-updated? (state/sub :favorites/updated?)
           _favorites-updated? (state/sub :favorites/updated?)
           favorited? (page-handler/favorited? page-name)
           favorited? (page-handler/favorited? page-name)
           developer-mode? (state/sub [:ui/developer-mode?])
           developer-mode? (state/sub [:ui/developer-mode?])

+ 2 - 2
src/main/frontend/components/plugins.cljs

@@ -1405,8 +1405,8 @@
 
 
 (defn open-waiting-updates-modal!
 (defn open-waiting-updates-modal!
   []
   []
-  (state/set-sub-modal!
-    (fn [_close!]
+  (shui/dialog-open!
+    (fn []
       (waiting-coming-updates))
       (waiting-coming-updates))
     {:center? true}))
     {:center? true}))
 
 

+ 3 - 8
src/main/frontend/components/plugins.css

@@ -451,21 +451,16 @@
   }
   }
 
 
   &-waiting-updates {
   &-waiting-updates {
-    margin: -15px;
-
     > ul {
     > ul {
       li {
       li {
-        user-select: none;
-        justify-content: space-between;
-        opacity: .9;
+        @apply select-none justify-between opacity-90;
 
 
         sup {
         sup {
-          padding-left: 8px;
-          font-weight: 400;
+          @apply pl-2 font-medium;
         }
         }
 
 
         &:hover, &.checked {
         &:hover, &.checked {
-          opacity: 1;
+          @apply opacity-100;
         }
         }
       }
       }
     }
     }

+ 99 - 80
src/main/frontend/components/property.cljs

@@ -15,7 +15,6 @@
             [frontend.handler.property :as property-handler]
             [frontend.handler.property :as property-handler]
             [frontend.handler.page :as page-handler]
             [frontend.handler.page :as page-handler]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.modules.shortcut.core :as shortcut]
-            [frontend.search :as search]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.ui :as ui]
             [frontend.util :as util]
             [frontend.util :as util]
@@ -42,7 +41,7 @@
           (:block/uuid page))))))
           (:block/uuid page))))))
 
 
 (rum/defc class-select
 (rum/defc class-select
-  [*property-schema schema-classes {:keys [multiple-choices? save-property-fn]
+  [*property-schema schema-classes {:keys [multiple-choices? save-property-fn disabled?]
                                     :or {multiple-choices? true}}]
                                     :or {multiple-choices? true}}]
   [:div.flex.flex-1.col-span-3
   [:div.flex.flex-1.col-span-3
    (let [content-fn
    (let [content-fn
@@ -93,7 +92,9 @@
              (select/select opts)))]
              (select/select opts)))]
 
 
     [:div.flex.flex-1.cursor-pointer
     [:div.flex.flex-1.cursor-pointer
-     {:on-click #(shui/popup-show! (.-target %) content-fn)}
+     {:on-click (if disabled?
+                  (constantly nil)
+                  #(shui/popup-show! (.-target %) content-fn))}
      (if (seq schema-classes)
      (if (seq schema-classes)
        [:div.flex.flex-1.flex-row.items-center.flex-wrap.gap-2
        [:div.flex.flex-1.flex-row.items-center.flex-wrap.gap-2
         (for [class schema-classes]
         (for [class schema-classes]
@@ -127,27 +128,27 @@
 
 
 (rum/defc schema-type <
 (rum/defc schema-type <
   shortcut/disable-all-shortcuts
   shortcut/disable-all-shortcuts
-  [property {:keys [*property-name *property-schema built-in-property? disabled?
+  [property {:keys [*property-name *property-schema built-in? disabled?
                     show-type-change-hints? in-block-container? block *show-new-property-config?
                     show-type-change-hints? in-block-container? block *show-new-property-config?
                     default-open?]}]
                     default-open?]}]
   (let [property-name (or (and *property-name @*property-name) (:block/original-name property))
   (let [property-name (or (and *property-name @*property-name) (:block/original-name property))
         property-schema (or (and *property-schema @*property-schema) (:block/schema property))
         property-schema (or (and *property-schema @*property-schema) (:block/schema property))
         schema-types (->> (concat db-property-type/user-built-in-property-types
         schema-types (->> (concat db-property-type/user-built-in-property-types
-                                  (when built-in-property?
+                                  (when built-in?
                                     db-property-type/internal-built-in-property-types))
                                     db-property-type/internal-built-in-property-types))
                           (map (fn [type]
                           (map (fn [type]
                                  {:label (property-type-label type)
                                  {:label (property-type-label type)
-                                  :disabled disabled?
-                                  :value type
-                                  :selected (= type (:type property-schema))})))]
+                                  :value type})))]
     [:div {:class (if in-block-container? "flex flex-1" "flex items-center col-span-2")}
     [:div {:class (if in-block-container? "flex flex-1" "flex items-center col-span-2")}
      (shui/select
      (shui/select
-      {:default-open (boolean default-open?)
-       :on-value-change
-       (fn [v]
-         (let [type (keyword (string/lower-case v))
-               update-schema-fn (apply comp
-                                       #(assoc % :type type)
+      (cond->
+       {:default-open (boolean default-open?)
+        :disabled disabled?
+        :on-value-change
+        (fn [v]
+          (let [type (keyword (string/lower-case v))
+                update-schema-fn (apply comp
+                                        #(assoc % :type type)
                                              ;; always delete previous closed values as they
                                              ;; always delete previous closed values as they
                                              ;; are not valid for the new type
                                              ;; are not valid for the new type
                                        #(dissoc % :values)
                                        #(dissoc % :values)
@@ -164,7 +165,8 @@
              (p/do!
              (p/do!
               (when block
               (when block
                 (pv/exit-edit-property))
                 (pv/exit-edit-property))
-              (reset! *show-new-property-config? false)
+              (when *show-new-property-config?
+                (reset! *show-new-property-config? false))
               (components-pu/update-property! property property-name schema)
               (components-pu/update-property! property property-name schema)
               (when block
               (when block
                 (let [id (str "ls-property-" (:db/id block) "-" (:db/id property) "-editor")]
                 (let [id (str "ls-property-" (:db/id block) "-" (:db/id property) "-editor")]
@@ -179,15 +181,15 @@
         {:placeholder "Select a schema type"}))
         {:placeholder "Select a schema type"}))
       (shui/select-content
       (shui/select-content
        (shui/select-group
        (shui/select-group
-        (for [{:keys [label value disabled]} schema-types]
-          (shui/select-item {:value value :disabled disabled} label)))))
+        (for [{:keys [label value]} schema-types]
+          (shui/select-item {:value value} label)))))
 
 
      (when show-type-change-hints?
      (when show-type-change-hints?
        (ui/tippy {:html        "Changing the property type clears some property configurations."
        (ui/tippy {:html        "Changing the property type clears some property configurations."
                   :class       "tippy-hover ml-2"
                   :class       "tippy-hover ml-2"
                   :interactive true
                   :interactive true
                   :disabled    false}
                   :disabled    false}
-                 (svg/info)))]))
+                 (svg/info))))]))
 
 
 (rum/defcs ^:large-vars/cleanup-todo property-config
 (rum/defcs ^:large-vars/cleanup-todo property-config
   "All changes to a property must update the db and the *property-schema. Failure to do
   "All changes to a property must update the db and the *property-schema. Failure to do
@@ -215,12 +217,11 @@
                    (when-let [*show-property-config? (:*show-new-property-config? (last (:rum/args state)))]
                    (when-let [*show-property-config? (:*show-new-property-config? (last (:rum/args state)))]
                      (reset! *show-property-config? false))
                      (reset! *show-property-config? false))
                    state)}
                    state)}
-  [state property {:keys [inline-text add-new-property? _*show-new-property-config?] :as opts}]
+  [state property {:keys [inline-text add-new-property?] :as opts}]
   (let [values (rum/react (::values state))]
   (let [values (rum/react (::values state))]
     (when-not (= :loading values)
     (when-not (= :loading values)
       (let [*property-name (::property-name state)
       (let [*property-name (::property-name state)
             *property-schema (::property-schema state)
             *property-schema (::property-schema state)
-            built-in-property? (contains? db-property/built-in-properties-keys-str (:block/original-name property))
             property (db/sub-block (:db/id property))
             property (db/sub-block (:db/id property))
             built-in? (ldb/built-in? property)
             built-in? (ldb/built-in? property)
             disabled? (or built-in? config/publishing?)
             disabled? (or built-in? config/publishing?)
@@ -275,7 +276,7 @@
                         (svg/help-circle))]
                         (svg/help-circle))]
              (schema-type property {:*property-name *property-name
              (schema-type property {:*property-name *property-name
                                     :*property-schema *property-schema
                                     :*property-schema *property-schema
-                                    :built-in-property? built-in-property?
+                                    :built-in? built-in?
                                     :disabled? disabled?
                                     :disabled? disabled?
                                     :show-type-change-hints? true}))]
                                     :show-type-change-hints? true}))]
 
 
@@ -364,18 +365,21 @@
                                     (swap! *property-schema assoc :hide? (not hide?))
                                     (swap! *property-schema assoc :hide? (not hide?))
                                     (save-property-fn))})])
                                     (save-property-fn))})])
 
 
-          [:div.grid.grid-cols-4.gap-1.items-start.leading-8
-           [:label "Description:"]
-           [:div.col-span-3
-            (if (and disabled? inline-text)
-              (inline-text {} :markdown (:description @*property-schema))
-              [:div.mt-1
-               (shui/textarea
-                {:on-change     (fn [e]
-                                  (swap! *property-schema assoc :description (util/evalue e)))
-                 :on-blur       save-property-fn
-                 :disabled      disabled?
-                 :default-value (:description @*property-schema)})])]]]]))))
+          (let [description (:description @*property-schema)]
+            (when (or (not disabled?)
+                    (and disabled? (not (string/blank? description))))
+              [:div.grid.grid-cols-4.gap-1.items-start.leading-8
+               [:label "Description:"]
+               [:div.col-span-3
+                (if (and disabled? inline-text)
+                  (inline-text {} :markdown description)
+                  [:div.mt-1
+                   (shui/textarea
+                     {:on-change (fn [e]
+                                   (swap! *property-schema assoc :description (util/evalue e)))
+                      :on-blur save-property-fn
+                      :disabled disabled?
+                      :default-value description})])]]))]]))))
 
 
 (defn- get-property-from-db [name]
 (defn- get-property-from-db [name]
   (when-not (string/blank? name)
   (when-not (string/blank? name)
@@ -388,15 +392,16 @@
   (let [repo (state/get-current-repo)]
   (let [repo (state/get-current-repo)]
     ;; existing property selected or entered
     ;; existing property selected or entered
     (if-let [property (get-property-from-db property-name)]
     (if-let [property (get-property-from-db property-name)]
-      (if (contains? db-property/hidden-built-in-properties (keyword property-name))
-        (do (notification/show! "This is a built-in property that can't be used." :error)
+      (if (and (not (get-in property [:block/schema :public?]))
+               (ldb/built-in? property))
+        (do (notification/show! "This is a private built-in property that can't be used." :error)
             (pv/exit-edit-property))
             (pv/exit-edit-property))
         ;; Both conditions necessary so that a class can add its own page properties
         ;; Both conditions necessary so that a class can add its own page properties
         (when (and (contains? (:block/type entity) "class") class-schema?)
         (when (and (contains? (:block/type entity) "class") class-schema?)
-          (pv/<add-property! entity (:db/ident property) "" {:class-schema? class-schema?
-                                                             ;; Only enter property names from sub-modal as inputting
-                                                             ;; property values is buggy in sub-modal
-                                                             :exit-edit? page-configure?})))
+          (pv/<add-property! entity property-name "" {:class-schema? class-schema?
+                                                     ;; Only enter property names from sub-modal as inputting
+                                                     ;; property values is buggy in sub-modal
+                                                      :exit-edit? page-configure?})))
       ;; new property entered
       ;; new property entered
       (if (db-property/valid-property-name? property-name)
       (if (db-property/valid-property-name? property-name)
         (if (and (contains? (:block/type entity) "class") page-configure?)
         (if (and (contains? (:block/type entity) "class") page-configure?)
@@ -409,11 +414,17 @@
 
 
 (rum/defc property-select
 (rum/defc property-select
   [exclude-properties on-chosen input-opts]
   [exclude-properties on-chosen input-opts]
-  (let [[properties set-properties!] (rum/use-state nil)]
+  (let [[properties set-properties!] (rum/use-state nil)
+        [excluded-properties set-excluded-properties!] (rum/use-state nil)]
     (rum/use-effect!
     (rum/use-effect!
      (fn []
      (fn []
-       (p/let [properties (search/get-all-properties)]
-         (set-properties! (remove exclude-properties properties))))
+       (p/let [properties (db-async/<db-based-get-all-properties (state/get-current-repo))]
+         (set-properties! (map :block/original-name (remove exclude-properties properties)))
+         (set-excluded-properties! (->> properties
+                                        (filter exclude-properties)
+                                        ;; lower case b/c of case insensitive name lookups
+                                        (map (comp string/lower-case :block/original-name))
+                                        set))))
      [])
      [])
     [:div.ls-property-add.flex.flex-row.items-center
     [:div.ls-property-add.flex.flex-row.items-center
     [:span.bullet-container.cursor [:span.bullet]]
     [:span.bullet-container.cursor [:span.bullet]]
@@ -423,7 +434,7 @@
                      :dropdown? true
                      :dropdown? true
                      :close-modal? false
                      :close-modal? false
                      :show-new-when-not-exact-match? true
                      :show-new-when-not-exact-match? true
-                     :exact-match-exclude-items exclude-properties
+                     :exact-match-exclude-items (fn [s] (contains? excluded-properties (string/lower-case s)))
                      :input-default-placeholder "Add property"
                      :input-default-placeholder "Add property"
                      :on-chosen on-chosen
                      :on-chosen on-chosen
                      :input-opts input-opts})]]))
                      :input-opts input-opts})]]))
@@ -435,23 +446,23 @@
                      (reset! *property-key nil))
                      (reset! *property-key nil))
                    state)}
                    state)}
   shortcut/disable-all-shortcuts
   shortcut/disable-all-shortcuts
-  [state entity *property-key *property-value {:keys [class-schema? _page-configure? in-block-container?]
+  [state entity *property-key *property-value {:keys [class-schema? in-block-container? page?]
                                                :as opts}]
                                                :as opts}]
   (let [*show-new-property-config? (::show-new-property-config? state)
   (let [*show-new-property-config? (::show-new-property-config? state)
         entity-properties (->> (keys (:block/properties entity))
         entity-properties (->> (keys (:block/properties entity))
                                (map #(:block/original-name (db/entity %)))
                                (map #(:block/original-name (db/entity %)))
                                (remove nil?)
                                (remove nil?)
                                (set))
                                (set))
-        existing-tag-alias (reduce (fn [acc prop]
-                                     (if (seq (get entity (get-in db-property/built-in-properties [prop :attribute])))
-                                       (if-let [name (get-in db-property/built-in-properties [prop :original-name])]
-                                         (conj acc name)
-                                         acc)
-                                       acc))
-                                   #{}
-                                   [:tags :alias])
-        exclude-properties* (set/union entity-properties existing-tag-alias)
-        exclude-properties (set/union exclude-properties* (set (map string/lower-case exclude-properties*)))]
+        existing-tag-alias (->> [:block/tags :block/alias]
+                                (map db-property/built-in-properties)
+                                (keep #(when (get entity (:attribute %)) (:original-name %)))
+                                set)
+        exclude-property-names (set/union entity-properties existing-tag-alias)
+        exclude-properties (fn [m]
+                             (or (contains? exclude-property-names (:block/original-name m))
+                                 ;; Filters out properties from being in wrong :view-context
+                                 (and in-block-container? (= :page (get-in m [:block/schema :view-context])))
+                                 (and page? (= :block (get-in m [:block/schema :view-context])))))]
     [:div.ls-property-input.flex.flex-1.flex-row.items-center.flex-wrap.gap-1
     [:div.ls-property-input.flex.flex-1.flex-row.items-center.flex-wrap.gap-1
      (if in-block-container? {:style {:padding-left 22}} {})
      (if in-block-container? {:style {:padding-left 22}} {})
      (if @*property-key
      (if @*property-key
@@ -519,7 +530,7 @@
                          (reset! *new-property? true))}
                          (reset! *new-property? true))}
             [:div.flex.flex-row.items-center {:style {:padding-left 1}}
             [:div.flex.flex-row.items-center {:style {:padding-left 1}}
              (ui/icon "plus" {:size 15})
              (ui/icon "plus" {:size 15})
-             [:div.ml-1.text-sm {:style {:padding-left 2}} "Add property"]]]
+             [:div.ml-1 {:style {:padding-left 2}} "Add property"]]]
 
 
            :else
            :else
            [:div {:style {:height 28}}]))])))
            [:div {:style {:height 28}}]))])))
@@ -580,6 +591,7 @@
                                                                                (:db/ident property)
                                                                                (:db/ident property)
                                                                                {:properties {:logseq.property/icon icon}})]
                                                                                {:properties {:logseq.property/icon icon}})]
                                 (shui/popup-hide! id))))}))]
                                 (shui/popup-hide! id))))}))]
+
        (shui/trigger-as :button
        (shui/trigger-as :button
                         (-> (when-not config/publishing?
                         (-> (when-not config/publishing?
                               {:on-click #(shui/popup-show! (.-target %) content-fn {:as-dropdown? true :auto-focus? true})})
                               {:on-click #(shui/popup-show! (.-target %) content-fn {:as-dropdown? true :auto-focus? true})})
@@ -595,29 +607,34 @@
         (:block/original-name property)]
         (:block/original-name property)]
 
 
        (shui/trigger-as :a
        (shui/trigger-as :a
-                        {:tabIndex 0
-                         :title (str "Configure property: " (:block/original-name property))
-                         :class "property-k flex select-none jtrigger pl-2"
-                         :on-pointer-down (fn [^js e]
-                                            (when (util/meta-key? e)
-                                              (route-handler/redirect-to-page! (:block/name property))
-                                              (.preventDefault e)))
-                         :on-click (fn [^js e]
-                                     (shui/popup-show!
-                                      (.-target e)
-                                      (fn [_]
-                                        [:div.p-2
-                                         [:h2.text-lg.font-medium.mb-2.p-1 "Configure property"]
-                                         (property-config property
-                                                          {:inline-text inline-text
-                                                           :page-cp page-cp})])
-                                      {:content-props {:class "property-configure-popup-content"
-                                                       :collisionPadding {:bottom 10 :top 10}
-                                                       :avoidCollisions true
-                                                       :align "start"}
-                                       :auto-side? true
-                                       :auto-focus? true}))}
-                        (:block/original-name property)))]))
+         {:tabIndex 0
+          :title (str "Configure property: " (:block/original-name property))
+          :class "property-k flex select-none jtrigger pl-2"
+          :on-pointer-down (fn [^js e]
+                             (when (util/meta-key? e)
+                               (route-handler/redirect-to-page! (:block/name property))
+                               (.preventDefault e)))
+          :on-click (fn [^js e]
+                      (shui/popup-show!
+                        (.-target e)
+                        (fn [{:keys [id]}]
+                          [:div.p-2
+                           [:h2.text-lg.font-medium.mb-2.p-1 "Configure property"]
+                           [:span.close.absolute.right-2.top-2
+                            (shui/button
+                              {:variant :ghost :size :sm :class "!w-4 !h-6"
+                               :on-click #(shui/popup-hide! id)}
+                              (shui/tabler-icon "x" {:size 16}))]
+                           (property-config property
+                             {:inline-text inline-text
+                              :page-cp page-cp})])
+                        {:content-props {:class "property-configure-popup-content"
+                                         :collisionPadding {:bottom 10 :top 10}
+                                         :avoidCollisions true
+                                         :align "start"}
+                         :auto-side? true
+                         :auto-focus? true}))}
+         (:block/original-name property)))]))
 
 
 (defn- resolve-linked-block-if-exists
 (defn- resolve-linked-block-if-exists
   "Properties will be updated for the linked page instead of the refed block.
   "Properties will be updated for the linked page instead of the refed block.
@@ -708,8 +725,10 @@
         alias-properties (when (seq alias)
         alias-properties (when (seq alias)
                            [[:block/alias alias]])
                            [[:block/alias alias]])
         remove-built-in-properties (fn [properties]
         remove-built-in-properties (fn [properties]
-                                     (remove (fn [property-id]
-                                               (contains? db-property/hidden-built-in-properties property-id))
+                                     (remove (fn [id]
+                                               (when-let [ent (db/entity id)]
+                                                   (and (not (get-in ent [:block/schema :public?]))
+                                                        (ldb/built-in? ent))))
                                              properties))
                                              properties))
         {:keys [classes all-classes classes-properties]} (db-property-handler/get-block-classes-properties (:db/id block))
         {:keys [classes all-classes classes-properties]} (db-property-handler/get-block-classes-properties (:db/id block))
         one-class? (= 1 (count classes))
         one-class? (= 1 (count classes))

+ 1 - 1
src/main/frontend/components/property.css

@@ -47,7 +47,7 @@
 }
 }
 
 
 .ls-properties-area {
 .ls-properties-area {
-    @apply grid gap-2 py-2;
+    @apply grid gap-0.5 pt-2 pb-1.5;
 
 
     .property-pair {
     .property-pair {
         @apply grid grid-cols-5 gap-1;
         @apply grid grid-cols-5 gap-1;

+ 5 - 5
src/main/frontend/components/query_table.cljs

@@ -72,12 +72,12 @@
   done"
   done"
   [current-block {:keys [db-graph?]}]
   [current-block {:keys [db-graph?]}]
   (let [properties (:block/properties current-block)
   (let [properties (:block/properties current-block)
-        p-desc? (pu/lookup properties :query-sort-desc)
+        p-desc? (pu/lookup properties :logseq.property/query-sort-desc)
         desc? (if (some? p-desc?) p-desc? true)
         desc? (if (some? p-desc?) p-desc? true)
         properties (:block/properties current-block)
         properties (:block/properties current-block)
-        query-sort-by (pu/lookup properties :query-sort-by)
+        query-sort-by (pu/lookup properties :logseq.property/query-sort-by)
         ;; Starting with #6105, we started putting properties under namespaces.
         ;; Starting with #6105, we started putting properties under namespaces.
-        nlp-date? (and (not db-graph?) (pu/lookup properties :logseq.query/nlp-date))
+        nlp-date? (and (not db-graph?) (pu/lookup-by-name properties :logseq.query/nlp-date))
         sort-by-column (or (if (uuid? query-sort-by) query-sort-by (keyword query-sort-by))
         sort-by-column (or (if (uuid? query-sort-by) query-sort-by (keyword query-sort-by))
                            (if (query-dsl/query-contains-filter? (:block/content current-block) "sort-by")
                            (if (query-dsl/query-contains-filter? (:block/content current-block) "sort-by")
                              nil
                              nil
@@ -113,7 +113,7 @@
                             ;; TODO: Support additional hidden properties e.g. from user config
                             ;; TODO: Support additional hidden properties e.g. from user config
                             ;; or gp-property/built-in-extended properties
                             ;; or gp-property/built-in-extended properties
                             (set (map #(db-pu/get-built-in-property-uuid repo %)
                             (set (map #(db-pu/get-built-in-property-uuid repo %)
-                                      db-property/built-in-properties-keys-str))
+                                      (keys db-property/built-in-properties)))
                             (conj (file-property-handler/built-in-properties) :template))
                             (conj (file-property-handler/built-in-properties) :template))
         prop-keys* (->> (distinct (mapcat keys (map :block/properties result)))
         prop-keys* (->> (distinct (mapcat keys (map :block/properties result)))
                         (remove hidden-properties))
                         (remove hidden-properties))
@@ -124,7 +124,7 @@
 
 
 (defn get-columns [current-block result {:keys [page?]}]
 (defn get-columns [current-block result {:keys [page?]}]
   (let [properties (:block/properties current-block)
   (let [properties (:block/properties current-block)
-        query-properties (pu/lookup properties :query-properties)
+        query-properties (pu/lookup properties :logseq.property/query-properties)
         query-properties (if (config/db-based-graph? (state/get-current-repo))
         query-properties (if (config/db-based-graph? (state/get-current-repo))
                            query-properties
                            query-properties
                            (some-> query-properties
                            (some-> query-properties

+ 134 - 103
src/main/frontend/components/repo.cljs

@@ -65,10 +65,9 @@
 
 
      [:div.controls
      [:div.controls
       [:div.flex.flex-row.items-center
       [:div.flex.flex-row.items-center
-       (let [current-repo (state/get-current-repo)
-             db-graph? (config/db-based-graph? current-repo)
-             manager? (and db-graph? (user-handler/manager? current-repo))]
-         (when-not (and db-graph? only-cloud? (not manager?))
+       (let [db-graph? (config/db-based-graph? url)
+             manager? (and db-graph? (user-handler/manager? url))]
+         (when-not (and only-cloud? (not manager?))
            (ui/tippy {:html [:div.text-sm.max-w-xs
            (ui/tippy {:html [:div.text-sm.max-w-xs
                              (cond
                              (cond
                                only-cloud?
                                only-cloud?
@@ -90,10 +89,10 @@
                                                           (str "Are you sure to permanently delete the graph \"" url "\" from Logseq?")
                                                           (str "Are you sure to permanently delete the graph \"" url "\" from Logseq?")
                                                           :else
                                                           :else
                                                           "")
                                                           "")
-                                         unlink-or-remote-fn (fn []
+                                         unlink-or-remote-fn! (fn []
                                                                (repo-handler/remove-repo! repo)
                                                                (repo-handler/remove-repo! repo)
-                                                               (state/pub-event! [:graph/unlinked repo current-repo]))
-                                         action-confirm-fn (if only-cloud?
+                                                               (state/pub-event! [:graph/unlinked repo (state/get-current-repo)]))
+                                         action-confirm-fn! (if only-cloud?
                                                              (fn []
                                                              (fn []
                                                                (when (or manager? (not db-graph?))
                                                                (when (or manager? (not db-graph?))
                                                                  (let [delete-graph (if db-graph?
                                                                  (let [delete-graph (if db-graph?
@@ -104,21 +103,18 @@
                                                                        (state/delete-repo! repo)
                                                                        (state/delete-repo! repo)
                                                                        (state/delete-remote-graph! repo)
                                                                        (state/delete-remote-graph! repo)
                                                                        (state/set-state! [:file-sync/remote-graphs :loading] false)))))
                                                                        (state/set-state! [:file-sync/remote-graphs :loading] false)))))
-                                                             unlink-or-remote-fn)
-                                         confirm-fn
+                                                             unlink-or-remote-fn!)
+                                         confirm-fn!
                                          (fn []
                                          (fn []
-                                           (ui/make-confirm-modal
-                                            {:title      [:div
-                                                          {:style {:max-width 700}}
-                                                          prompt-str]
-                                             :sub-title   [:div.small.mt-1
-                                                           "Notice that we can't recover this graph after being deleted. Make sure you have backups before deleting it."]
-                                             :on-confirm (fn [_ {:keys [close-fn]}]
-                                                           (close-fn)
-                                                           (action-confirm-fn))}))]
+                                           (-> (shui/dialog-confirm!
+                                                 [:p.font-medium.-my-4 prompt-str
+                                                  [:span.mt-1.flex.font-normal.opacity-40
+                                                   [:small "Notice that we can't recover this graph after being deleted. Make sure you have backups before deleting it."]]])
+                                             (p/then #(action-confirm-fn!))))]
+
                                      (if has-prompt?
                                      (if has-prompt?
-                                       (state/set-modal! (confirm-fn))
-                                       (unlink-or-remote-fn))))}
+                                       (confirm-fn!)
+                                       (unlink-or-remote-fn!))))}
                       (if only-cloud? "Remove (server)" "Unlink (local)")])))]]]))
                       (if only-cloud? "Remove (server)" "Unlink (local)")])))]]]))
 
 
 (rum/defc repos < rum/reactive
 (rum/defc repos < rum/reactive
@@ -127,8 +123,8 @@
         repos (state/sub [:me :repos])
         repos (state/sub [:me :repos])
         repos (util/distinct-by :url repos)
         repos (util/distinct-by :url repos)
         remotes (concat
         remotes (concat
-                 (state/sub :rtc/graphs)
-                 (state/sub [:file-sync/remote-graphs :graphs]))
+                  (state/sub :rtc/graphs)
+                  (state/sub [:file-sync/remote-graphs :graphs]))
         remotes-loading? (state/sub [:file-sync/remote-graphs :loading])
         remotes-loading? (state/sub [:file-sync/remote-graphs :loading])
         repos (if (and login? (seq remotes))
         repos (if (and login? (seq remotes))
                 (repo-handler/combine-local-&-remote-graphs repos remotes) repos)
                 (repo-handler/combine-local-&-remote-graphs repos remotes) repos)
@@ -147,11 +143,11 @@
 
 
          [:div.flex.flex-row.my-4
          [:div.flex.flex-row.my-4
           (when (or (nfs-handler/supported?)
           (when (or (nfs-handler/supported?)
-                    (mobile-util/native-platform?))
+                  (mobile-util/native-platform?))
             [:div.mr-8
             [:div.mr-8
              (ui/button
              (ui/button
-              (t :open-a-directory)
-              :on-click #(state/pub-event! [:graph/setup-a-repo]))])]]
+               (t :open-a-directory)
+               :on-click #(state/pub-event! [:graph/setup-a-repo]))])]]
 
 
         (when (and (file-sync/enable-sync?) login?)
         (when (and (file-sync/enable-sync?) login?)
           [:div
           [:div
@@ -160,13 +156,13 @@
             [:h2.text-lg.font-medium.my-4 (t :graph/remote-graphs)]
             [:h2.text-lg.font-medium.my-4 (t :graph/remote-graphs)]
             [:div
             [:div
              (ui/button
              (ui/button
-              [:span.flex.items-center "Refresh"
-               (when remotes-loading? [:small.pl-2 (ui/loading nil)])]
-              :background "gray"
-              :disabled remotes-loading?
-              :on-click (fn []
-                          (file-sync/load-session-graphs)
-                          (rtc-handler/<get-remote-graphs)))]]
+               [:span.flex.items-center "Refresh"
+                (when remotes-loading? [:small.pl-2 (ui/loading nil)])]
+               :background "gray"
+               :disabled remotes-loading?
+               :on-click (fn []
+                           (file-sync/load-session-graphs)
+                           (rtc-handler/<get-remote-graphs)))]]
            (repos-inner remote-graphs)])]]
            (repos-inner remote-graphs)])]]
       (widgets/add-graph))))
       (widgets/add-graph))))
 
 
@@ -180,19 +176,19 @@
   (let [switch-repos (if-not (nil? current-repo)
   (let [switch-repos (if-not (nil? current-repo)
                        (remove (fn [repo] (= current-repo (:url repo))) repos) repos) ; exclude current repo
                        (remove (fn [repo] (= current-repo (:url repo))) repos) repos) ; exclude current repo
         repo-links (mapv
         repo-links (mapv
-                    (fn [{:keys [url remote? rtc-graph? GraphName GraphUUID] :as graph}]
-                      (let [local? (config/local-file-based-graph? url)
-                            db-only? (config/db-based-graph? url)
-                            repo-url (cond
-                                       local? (db/get-repo-name url)
-                                       db-only? url
+                     (fn [{:keys [url remote? rtc-graph? GraphName GraphUUID] :as graph}]
+                       (let [local? (config/local-file-based-graph? url)
+                             db-only? (config/db-based-graph? url)
+                             repo-url (cond
+                                        local? (db/get-repo-name url)
+                                        db-only? url
                                        :else GraphName)
                                        :else GraphName)
                             short-repo-name (if (or local? db-only?)
                             short-repo-name (if (or local? db-only?)
                                               (text-util/get-graph-name-from-path repo-url)
                                               (text-util/get-graph-name-from-path repo-url)
                                               GraphName)
                                               GraphName)
                             downloading? (and downloading-graph-id (= GraphUUID downloading-graph-id))]
                             downloading? (and downloading-graph-id (= GraphUUID downloading-graph-id))]
                         (when short-repo-name
                         (when short-repo-name
-                          {:title        [:span.flex.items-center.whitespace-nowrap short-repo-name
+                          {:title        [:span.flex.items-center.title-wrap short-repo-name
                                           (when remote? [:span.pl-1.flex.items-center
                                           (when remote? [:span.pl-1.flex.items-center
                                                          {:title (str "<" GraphName "> #" GraphUUID)}
                                                          {:title (str "<" GraphName "> #" GraphUUID)}
                                                          (ui/icon "cloud" {:size 18})
                                                          (ui/icon "cloud" {:size 18})
@@ -259,68 +255,93 @@
             downloading-graph-id (state/sub :rtc/downloading-graph-uuid)
             downloading-graph-id (state/sub :rtc/downloading-graph-uuid)
             repos (if (and (or (seq remotes) (seq rtc-graphs)) login?)
             repos (if (and (or (seq remotes) (seq rtc-graphs)) login?)
                     (repo-handler/combine-local-&-remote-graphs repos (concat remotes rtc-graphs)) repos)
                     (repo-handler/combine-local-&-remote-graphs repos (concat remotes rtc-graphs)) repos)
-            links (repos-dropdown-links repos current-repo downloading-graph-id multiple-windows? opts)
-            render-content (fn [{:keys [toggle-fn]}]
-                             (let [remote? (:remote? (first (filter #(= current-repo (:url %)) repos)))
-                                   repo-name (db/get-repo-name current-repo)
-                                   short-repo-name (if repo-name
-                                                     (db/get-short-repo-name repo-name)
-                                                     "Select a Graph")]
-                               [:a.item.group.flex.items-center.p-2.text-sm.font-medium.rounded-md
-
-                                {:on-click (fn [_e]
-                                             (check-multiple-windows? state)
-                                             (toggle-fn))
-                                 :title    repo-name}       ;; show full path on hover
-                                [:div.flex.flex-row.items-center
-                                 [:div.flex.relative.graph-icon.rounded
-                                  (let [icon "database"
-                                        opts {:size 14}]
-                                    (ui/icon icon opts))]
+            items-fn #(repos-dropdown-links repos current-repo downloading-graph-id multiple-windows? opts)
+            header-fn #(when (> (count repos) 1)            ; show switch to if there are multiple repos
+                         [:div.font-medium.text-sm.opacity-50.px-1.py-1.flex.flex-row.justify-between.items-center
+                          [:div (t :left-side-bar/switch)]
 
 
-                                 [:div.graphs
-                                  [:span#repo-switch.block.pr-2.whitespace-nowrap
-                                   [:span [:span#repo-name.font-medium
-                                           [:span.overflow-hidden.text-ellipsis (if (= config/demo-repo short-repo-name) "Demo" short-repo-name)]
-                                           (when remote? [:span.pl-1 (ui/icon "cloud")])]]
-                                   [:span.dropdown-caret.ml-2 {:style {:border-top-color "#6b7280"}}]]]]]))
-            links-header (cond->
-                          {:z-index 1000
-                           :modal-class (util/hiccup->class
-                                         "origin-top-right.absolute.left-0.mt-2.rounded-md.shadow-lg")}
-                           (> (count repos) 1)              ; show switch to if there are multiple repos
-                           (assoc :links-header [:div.font-medium.text-sm.opacity-70.px-4.pt-2.pb-1.flex.flex-row.justify-between.items-center
-                                                 [:div (t :left-side-bar/switch)]
-                                                 (when (and (file-sync/enable-sync?) login?)
-                                                   (if remotes-loading?
-                                                     (ui/loading "")
-                                                     [:a.flex {:title "Refresh remote graphs"
-                                                               :on-click (fn []
-                                                                           (file-sync/load-session-graphs)
-                                                                           (rtc-handler/<get-remote-graphs))}
-                                                      (ui/icon "refresh")]))]))]
+                          (when (and (file-sync/enable-sync?) login?)
+                            (if remotes-loading?
+                              (ui/loading "")
+                              (shui/button
+                                {:variant :ghost
+                                 :size :sm
+                                 :title "Refresh remote graphs"
+                                 :class "!h-6 !px-1 relative right-[-4px]"
+                                 :on-click (fn []
+                                             (file-sync/load-session-graphs)
+                                             (rtc-handler/<get-remote-graphs))}
+                                (ui/icon "refresh" {:size 15}))))])]
         (when (seq repos)
         (when (seq repos)
-          (ui/dropdown-with-links render-content links links-header))))))
+          (let [remote? (and current-repo (:remote? (first (filter #(= current-repo (:url %)) repos))))
+                repo-name (when current-repo (db/get-repo-name current-repo))
+                short-repo-name (if current-repo
+                                  (db/get-short-repo-name repo-name)
+                                  "Select a Graph")]
+            (shui/trigger-as :a
+              {:tab-index 0
+               :class "item cp__repos-select-trigger"
+               :on-click (fn [^js e]
+                           (check-multiple-windows? state)
+                           (some-> (.-target e)
+                             (.closest "a.item")
+                             (shui/popup-show!
+                               (fn [{:keys [id]}]
+                                 [:<>
+                                  (header-fn)
+                                  (for [{:keys [hr item hover-detail title options icon]} (items-fn)]
+                                    (let [on-click' (:on-click options)
+                                          href' (:href options)]
+                                      (if hr
+                                        (shui/dropdown-menu-separator)
+                                        (shui/dropdown-menu-item
+                                          (assoc options
+                                            :title hover-detail
+                                            :on-click (fn [^js e]
+                                                        (when on-click'
+                                                          (when-not (false? (on-click' e))
+                                                            (shui/popup-hide! id)))))
+                                          (or item
+                                            (if href'
+                                              [:a.flex.items-center.w-full
+                                               {:href href' :on-click #(shui/popup-hide! id)
+                                                :style {:color "inherit"}} title]
+                                              [:span.flex.items-center.gap-1.w-full
+                                               icon [:div title]]))))))])
+                               {:as-dropdown? true
+                                :auto-focus? false
+                                :align "start"
+                                :content-props {:class "repos-list"}})))
+               :title repo-name}                            ;; show full path on hover
+              [:div.flex.flex-row.items-center
+               [:div.flex.relative.graph-icon.rounded
+                (shui/tabler-icon "database" {:size 15})]
+
+               [:div.repo-switch.block.pr-2.whitespace-nowrap
+                [:span.repo-name.font-medium
+                 [:span.overflow-hidden.text-ellipsis (if (= config/demo-repo short-repo-name) "Demo" short-repo-name)]
+                 (when remote? [:span.pl-1 (ui/icon "cloud")])]
+                [:span.dropdown-caret.ml-2 {:style {:border-top-color "#6b7280"}}]]])))))))
 
 
 (defn invalid-graph-name-warning
 (defn invalid-graph-name-warning
   []
   []
   (notification/show!
   (notification/show!
-   [:div
-    [:p "Graph name can't contain following reserved characters:"]
-    [:ul
-     [:li "< (less than)"]
-     [:li "> (greater than)"]
-     [:li ": (colon)"]
-     [:li "\" (double quote)"]
-     [:li "/ (forward slash)"]
-     [:li "\\ (backslash)"]
-     [:li "| (vertical bar or pipe)"]
-     [:li "? (question mark)"]
-     [:li "* (asterisk)"]
-     [:li "# (hash)"]
-     ;; `+` is used to encode path that includes `:` or `/`
-     [:li "+ (plus)"]]]
-   :warning false))
+    [:div
+     [:p "Graph name can't contain following reserved characters:"]
+     [:ul
+      [:li "< (less than)"]
+      [:li "> (greater than)"]
+      [:li ": (colon)"]
+      [:li "\" (double quote)"]
+      [:li "/ (forward slash)"]
+      [:li "\\ (backslash)"]
+      [:li "| (vertical bar or pipe)"]
+      [:li "? (question mark)"]
+      [:li "* (asterisk)"]
+      [:li "# (hash)"]
+      ;; `+` is used to encode path that includes `:` or `/`
+      [:li "+ (plus)"]]]
+    :warning false))
 
 
 (defn invalid-graph-name?
 (defn invalid-graph-name?
   "Returns boolean indicating if DB graph name is invalid. Must be kept in sync with invalid-graph-name-warning"
   "Returns boolean indicating if DB graph name is invalid. Must be kept in sync with invalid-graph-name-warning"
@@ -332,10 +353,17 @@
   (rum/local "" ::graph-name)
   (rum/local "" ::graph-name)
   (rum/local false ::cloud?)
   (rum/local false ::cloud?)
   (rum/local false ::creating-db?)
   (rum/local false ::creating-db?)
+  (rum/local (rum/create-ref) ::input-ref)
+  {:did-mount (fn [s]
+                (when-let [^js input (some-> @(::input-ref s)
+                                       (rum/deref))]
+                  (js/setTimeout #(.focus input) 32))
+                s)}
   [state]
   [state]
   (let [*creating-db? (::creating-db? state)
   (let [*creating-db? (::creating-db? state)
         *graph-name (::graph-name state)
         *graph-name (::graph-name state)
         *cloud? (::cloud? state)
         *cloud? (::cloud? state)
+        input-ref @(::input-ref state)
         new-db-f (fn []
         new-db-f (fn []
                    (when-not (or (string/blank? @*graph-name)
                    (when-not (or (string/blank? @*graph-name)
                                  @*creating-db?)
                                  @*creating-db?)
@@ -359,15 +387,18 @@
                                          (prn :debug :create-db-failed)
                                          (prn :debug :create-db-failed)
                                          (js/console.error error)))))
                                          (js/console.error error)))))
                            (reset! *creating-db? false)
                            (reset! *creating-db? false)
-                           (state/close-modal! {:force? true}))))))]
+                           (shui/dialog-close!))))))]
     [:div.new-graph.flex.flex-col.p-4.gap-4
     [:div.new-graph.flex.flex-col.p-4.gap-4
-     [:h1.title.mb-4 "Create new graph: "]
-     [:input.form-input {:value @*graph-name
-                         :auto-focus true
-                         :on-change #(reset! *graph-name (util/evalue %))
-                         :on-key-down (fn [^js e]
-                                        (when (= (gobj/get e "key") "Enter")
-                                          (new-db-f)))}]
+     (shui/input
+       {:value @*graph-name
+        :disabled @*creating-db?
+        :ref input-ref
+        :placeholder "your graph name"
+        :auto-focus true
+        :on-change #(reset! *graph-name (util/evalue %))
+        :on-key-down (fn [^js e]
+                       (when (= (gobj/get e "key") "Enter")
+                         (new-db-f)))})
      (when (user-handler/logged-in?)
      (when (user-handler/logged-in?)
        [:div.flex.flex-row.items-center.gap-1
        [:div.flex.flex-row.items-center.gap-1
         (shui/checkbox
         (shui/checkbox

+ 19 - 2
src/main/frontend/components/repo.css

@@ -10,6 +10,23 @@
 }
 }
 
 
 .repo-plus svg {
 .repo-plus svg {
-    display: inline;
-    transform: scale(0.7);
+  display: inline;
+  transform: scale(0.7);
 }
 }
+
+.ui__dropdown-menu-content {
+  &.repos-list {
+    @apply px-2;
+    @apply min-w-[260px] sm:max-w-[380px] max-h-[70vh];
+
+    .ui__dropdown-menu-item {
+      @apply overflow-hidden overflow-ellipsis;
+    }
+  }
+}
+
+.cp__repos-select {
+  &-trigger {
+    @apply flex items-center p-2 text-sm font-medium rounded-md;
+  }
+}

+ 1 - 1
src/main/frontend/config.cljs

@@ -28,7 +28,7 @@
 (goog-define TEST false)
 (goog-define TEST false)
 (def test? TEST)
 (def test? TEST)
 
 
-(goog-define ENABLE-FILE-SYNC-PRODUCTION false)
+(def ENABLE-FILE-SYNC-PRODUCTION false)
 
 
 ;; this is a feature flag to enable the account tab
 ;; this is a feature flag to enable the account tab
 ;; when it launches (when pro plan launches) it should be removed
 ;; when it launches (when pro plan launches) it should be removed

+ 13 - 7
src/main/frontend/db/async.cljs

@@ -15,7 +15,8 @@
             [frontend.date :as date]
             [frontend.date :as date]
             [cljs-time.core :as t]
             [cljs-time.core :as t]
             [cljs-time.format :as tf]
             [cljs-time.format :as tf]
-            [logseq.db :as ldb]))
+            [logseq.db :as ldb]
+            [clojure.string :as string]))
 
 
 (def <q db-async-util/<q)
 (def <q db-async-util/<q)
 (def <pull db-async-util/<pull)
 (def <pull db-async-util/<pull)
@@ -46,22 +47,27 @@
     (p/let [templates (<get-all-templates repo)]
     (p/let [templates (<get-all-templates repo)]
       (get templates name))))
       (get templates name))))
 
 
-(defn- <db-based-get-all-properties
-  "Return seq of property names. :block/type could be one of [property, class]."
+(defn <db-based-get-all-properties
+  "Return seq of all property names except for private built-in properties."
   [graph]
   [graph]
   (p/let [result (<q graph
   (p/let [result (<q graph
-                     '[:find [(pull ?e [:block/original-name]) ...]
+                     '[:find [(pull ?e [:block/original-name :block/schema :db/ident]) ...]
                        :where
                        :where
                        [?e :block/type "property"]
                        [?e :block/type "property"]
                        [?e :block/original-name]])]
                        [?e :block/original-name]])]
-    (map :block/original-name result)))
+    (->> result
+         ;; remove private built-in properties
+         (remove #(and (:db/ident %)
+                       (string/starts-with? (namespace (:db/ident %)) "logseq.")
+                       (not (get-in % [:block/schema :public?])))))))
 
 
-(defn <get-all-properties
+(defn <get-all-property-names
   "Returns a seq of property name strings"
   "Returns a seq of property name strings"
   []
   []
   (when-let [graph (state/get-current-repo)]
   (when-let [graph (state/get-current-repo)]
     (if (config/db-based-graph? graph)
     (if (config/db-based-graph? graph)
-      (<db-based-get-all-properties graph)
+      (p/let [properties (<db-based-get-all-properties graph)]
+        (map :block/original-name properties))
       (file-async/<file-based-get-all-properties graph))))
       (file-async/<file-based-get-all-properties graph))))
 
 
 (comment
 (comment

+ 7 - 7
src/main/frontend/db/model.cljs

@@ -980,7 +980,7 @@ independent of format as format specific heading characters are stripped"
 (defn get-whiteboard-id-nonces
 (defn get-whiteboard-id-nonces
   [repo page-name]
   [repo page-name]
   (let [key (if (config/db-based-graph? repo)
   (let [key (if (config/db-based-graph? repo)
-              (:block/uuid (db-utils/entity [:block/name "logseq.tldraw.shape"]))
+              (:block/uuid (db-utils/entity :logseq.property.tldraw/shape))
               :logseq.tldraw.shape)
               :logseq.tldraw.shape)
         page (db-utils/entity [:block/name (util/page-name-sanity-lc page-name)])]
         page (db-utils/entity [:block/name (util/page-name-sanity-lc page-name)])]
     (->> (:block/_page page)
     (->> (:block/_page page)
@@ -1000,33 +1000,33 @@ independent of format as format specific heading characters are stripped"
      [?page :block/uuid ?id]]
      [?page :block/uuid ?id]]
     (conn/get-db repo)))
     (conn/get-db repo)))
 
 
-(defn get-namespace-children
+(defn get-class-children
   [repo eid]
   [repo eid]
   (->>
   (->>
    (d/q '[:find [?children ...]
    (d/q '[:find [?children ...]
           :in $ ?parent %
           :in $ ?parent %
           :where
           :where
-          (namespace ?parent ?children)]
+          (class-parent ?parent ?children)]
         (conn/get-db repo)
         (conn/get-db repo)
         eid
         eid
-        (:namespace rules/rules))
+        (:class-parent rules/rules))
    distinct))
    distinct))
 
 
 ;; FIXME: async query
 ;; FIXME: async query
 (defn get-class-objects
 (defn get-class-objects
   [repo class-id]
   [repo class-id]
   (when-let [class (db-utils/entity repo class-id)]
   (when-let [class (db-utils/entity repo class-id)]
-    (if (first (:block/_namespace class))        ; has children classes
+    (if (first (:class/_parent class))        ; has children classes
       (d/q
       (d/q
        '[:find [?object ...]
        '[:find [?object ...]
          :in $ % ?parent
          :in $ % ?parent
          :where
          :where
-         (namespace ?parent ?c)
+         (class-parent ?parent ?c)
          (or-join [?object ?c]
          (or-join [?object ?c]
           [?object :block/tags ?parent]
           [?object :block/tags ?parent]
           [?object :block/tags ?c])]
           [?object :block/tags ?c])]
        (conn/get-db repo)
        (conn/get-db repo)
-       (:namespace rules/rules)
+       (:class-parent rules/rules)
        class-id)
        class-id)
       (map :db/id (:block/_tags class)))))
       (map :db/id (:block/_tags class)))))
 
 

+ 71 - 60
src/main/frontend/db/rtc/debug_ui.cljs

@@ -38,35 +38,35 @@
                     (js/setTimeout #(.removeAttribute btn "disabled") 2000)))}
                     (js/setTimeout #(.removeAttribute btn "disabled") 2000)))}
      [:div.flex.gap-2.flex-wrap.items-center.pb-3
      [:div.flex.gap-2.flex-wrap.items-center.pb-3
       (shui/button
       (shui/button
-        {:size :sm
-         :on-click (fn [_]
-                     (let [repo (state/get-current-repo)
-                           ^object worker @db-browser/*worker]
-                       (p/let [result (.rtc-get-debug-state worker repo)
-                               new-state (ldb/read-transit-str result)]
-                         (swap! debug-state (fn [old] (merge old new-state))))))}
-        (shui/tabler-icon "refresh") "local-state")
+       {:size :sm
+        :on-click (fn [_]
+                    (let [repo (state/get-current-repo)
+                          ^object worker @db-browser/*worker]
+                      (p/let [result (.rtc-get-debug-state worker repo)
+                              new-state (ldb/read-transit-str result)]
+                        (swap! debug-state (fn [old] (merge old new-state))))))}
+       (shui/tabler-icon "refresh") "local-state")
 
 
       (shui/button
       (shui/button
-        {:size :sm
-         :on-click
-         (fn [_]
-           (let [repo (state/get-current-repo)
-                 token (state/get-auth-id-token)
-                 ^object worker @db-browser/*worker]
-             (p/let [result (.rtc-get-graphs worker repo token)
-                     graph-list (bean/->clj result)]
-               (swap! debug-state assoc
-                 :remote-graphs
-                 (map
-                   #(into {}
-                      (filter second
-                        (select-keys % [:graph-uuid :graph-name
-                                        :graph-status
-                                        :graph<->user-user-type
-                                        :graph<->user-grant-by-user])))
-                   graph-list)))))}
-        (shui/tabler-icon "download") "graph-list")
+       {:size :sm
+        :on-click
+        (fn [_]
+          (let [repo (state/get-current-repo)
+                token (state/get-auth-id-token)
+                ^object worker @db-browser/*worker]
+            (p/let [result (.rtc-get-graphs worker repo token)
+                    graph-list (bean/->clj result)]
+              (swap! debug-state assoc
+                     :remote-graphs
+                     (map
+                      #(into {}
+                             (filter second
+                                     (select-keys % [:graph-uuid :graph-name
+                                                     :graph-status
+                                                     :graph<->user-user-type
+                                                     :graph<->user-grant-by-user])))
+                      graph-list)))))}
+       (shui/tabler-icon "download") "graph-list")
 
 
       (shui/button
       (shui/button
        {:size :sm
        {:size :sm
@@ -90,20 +90,20 @@
             :current-page (state/get-current-page)
             :current-page (state/get-current-page)
             :blocks-count (when-let [page (state/get-current-page)]
             :blocks-count (when-let [page (state/get-current-page)]
                             (count (:block/_page (db/entity [:block/name (util/page-name-sanity-lc page)]))))}
                             (count (:block/_page (db/entity [:block/name (util/page-name-sanity-lc page)]))))}
-         (fipp/pprint {:width 20})
-         with-out-str)]]
+           (fipp/pprint {:width 20})
+           with-out-str)]]
 
 
      (if (or (nil? rtc-state)
      (if (or (nil? rtc-state)
              (= :closed rtc-state))
              (= :closed rtc-state))
        (shui/button
        (shui/button
-         {:variant :outline
-          :class "text-green-rx-09 border-green-rx-10 hover:text-green-rx-10"
-          :on-click (fn []
-                      (let [token (state/get-auth-id-token)
-                            ^object worker @db-browser/*worker]
-                        (.rtc-start worker (state/get-current-repo) token
-                          (state/sub [:ui/developer-mode?]))))}
-         (shui/tabler-icon "player-play") "start")
+        {:variant :outline
+         :class "text-green-rx-09 border-green-rx-10 hover:text-green-rx-10"
+         :on-click (fn []
+                     (let [token (state/get-auth-id-token)
+                           ^object worker @db-browser/*worker]
+                       (.rtc-start worker (state/get-current-repo) token
+                                   (state/sub [:ui/developer-mode?]))))}
+        (shui/tabler-icon "player-play") "start")
 
 
        [:div.my-2.flex
        [:div.my-2.flex
         [:div.mr-2 (ui/button (str "send pending ops")
         [:div.mr-2 (ui/button (str "send pending ops")
@@ -118,11 +118,11 @@
                                    (p/let [result (.rtc-toggle-sync worker (state/get-current-repo))]
                                    (p/let [result (.rtc-toggle-sync worker (state/get-current-repo))]
                                      (swap! debug-state assoc :auto-push-updates? result))))})]
                                      (swap! debug-state assoc :auto-push-updates? result))))})]
         [:div (shui/button
         [:div (shui/button
-                {:variant :outline
-                 :class "text-red-rx-09 border-red-rx-08 hover:text-red-rx-10"
-                 :size :sm
-                 :on-click (fn [] (stop))}
-                (shui/tabler-icon "player-stop") "stop")]])
+               {:variant :outline
+                :class "text-red-rx-09 border-red-rx-08 hover:text-red-rx-10"
+                :size :sm
+                :on-click (fn [] (stop))}
+               (shui/tabler-icon "player-stop") "stop")]])
 
 
      (when (some? state)
      (when (some? state)
        [:hr]
        [:hr]
@@ -153,12 +153,23 @@
                  {:icon "download"
                  {:icon "download"
                   :class "mr-2"
                   :class "mr-2"
                   :on-click (fn []
                   :on-click (fn []
-                              (when-let [repo (:download-graph-to-repo state)]
+                              (when-let [graph-name (:download-graph-to-repo state)]
                                 (when-let [graph-uuid (:graph-uuid-to-download state)]
                                 (when-let [graph-uuid (:graph-uuid-to-download state)]
-                                  (prn :download-graph graph-uuid :to repo)
-                                  (let [token (state/get-auth-id-token)
-                                        ^object worker @db-browser/*worker]
-                                    (.rtc-download-graph worker repo token graph-uuid)))))})
+                                  (prn :download-graph graph-uuid :to graph-name)
+                                  (p/let [token (state/get-auth-id-token)
+                                          ^object worker @db-browser/*worker
+                                          download-info-uuid (.rtc-request-download-graph worker nil token graph-uuid)
+                                          result (.rtc-wait-download-graph-info-ready
+                                                  worker nil token download-info-uuid graph-uuid 60000)
+                                          {:keys [_download-info-uuid
+                                                  download-info-s3-url
+                                                  _download-info-tx-instant
+                                                  _download-info-t
+                                                  _download-info-created-at]
+                                           :as result} (ldb/read-transit-str result)]
+                                    (when (not= result :timeout)
+                                      (assert (some? download-info-s3-url) result)
+                                      (.rtc-download-graph-from-s3 worker graph-uuid graph-name download-info-s3-url))))))})
 
 
       [:b "➡"]
       [:b "➡"]
       [:div.flex.flex-row.items-center.gap-2
       [:div.flex.flex-row.items-center.gap-2
@@ -192,7 +203,7 @@
                                     token (state/get-auth-id-token)
                                     token (state/get-auth-id-token)
                                     remote-graph-name (:upload-as-graph-name state)
                                     remote-graph-name (:upload-as-graph-name state)
                                     ^js worker @db-browser/*worker]
                                     ^js worker @db-browser/*worker]
-                                (.rtc-upload-graph worker repo token remote-graph-name)))})
+                                (.rtc-async-upload-graph worker repo token remote-graph-name)))})
       [:b "➡️"]
       [:b "➡️"]
       [:input.form-input.my-2.py-1.w-32
       [:input.form-input.my-2.py-1.w-32
        {:on-change (fn [e] (swap! debug-state assoc :upload-as-graph-name (util/evalue e)))
        {:on-change (fn [e] (swap! debug-state assoc :upload-as-graph-name (util/evalue e)))
@@ -206,20 +217,20 @@
                  {:icon "trash"
                  {:icon "trash"
                   :on-click (fn []
                   :on-click (fn []
                               (-> (shui/dialog-confirm!
                               (-> (shui/dialog-confirm!
-                                    {:title [:p.flex.flex-col.gap-1
-                                             [:b "Are you sure delete current graph?"]
-                                             [:small.line-through.opacity-80 (state/get-current-repo)]]})
-                                (p/then #((when-let [graph-uuid (:graph-uuid-to-delete state)]
-                                            (let [token (state/get-auth-id-token)
-                                                  ^object worker @db-browser/*worker]
-                                              (prn ::delete-graph graph-uuid)
-                                              (.rtc-delete-graph worker token graph-uuid)))))))})
+                                   {:title [:p.flex.flex-col.gap-1
+                                            [:b "Are you sure delete current graph?"]
+                                            [:small.line-through.opacity-80 (state/get-current-repo)]]})
+                                  (p/then #((when-let [graph-uuid (:graph-uuid-to-delete state)]
+                                              (let [token (state/get-auth-id-token)
+                                                    ^object worker @db-browser/*worker]
+                                                (prn ::delete-graph graph-uuid)
+                                                (.rtc-delete-graph worker token graph-uuid)))))))})
 
 
       (shui/select
       (shui/select
-        {:on-value-change (fn [v]
-                            (some->> (parse-uuid v)
-                              str
-                              (swap! debug-state assoc :graph-uuid-to-delete)))}
+       {:on-value-change (fn [v]
+                           (some->> (parse-uuid v)
+                                    str
+                                    (swap! debug-state assoc :graph-uuid-to-delete)))}
        (shui/select-trigger
        (shui/select-trigger
         {:class "!px-2 !py-0 !h-8"}
         {:class "!px-2 !py-0 !h-8"}
         (shui/select-value
         (shui/select-value

+ 35 - 8
src/main/frontend/db_worker.cljs

@@ -575,25 +575,21 @@
          :target-user-uuids target-user-uuids
          :target-user-uuids target-user-uuids
          :target-user-emails target-user-emails)))))
          :target-user-emails target-user-emails)))))
 
 
-  (rtc-upload-graph
+  (rtc-async-upload-graph
    [this repo token remote-graph-name]
    [this repo token remote-graph-name]
    (let [d (p/deferred)]
    (let [d (p/deferred)]
      (when-let [conn (worker-state/get-datascript-conn repo)]
      (when-let [conn (worker-state/get-datascript-conn repo)]
        (async/go
        (async/go
          (try
          (try
-           (let [state (<? (rtc-core/<init-state repo token false))]
-             (<? (rtc-updown/<upload-graph state repo conn remote-graph-name))
+           (let [state (<? (rtc-core/<init-state repo token false))
+                 r (<? (rtc-updown/<async-upload-graph state repo conn remote-graph-name))]
              (rtc-db-listener/listen-db-to-generate-ops repo conn)
              (rtc-db-listener/listen-db-to-generate-ops repo conn)
-             (p/resolve! d :success))
-           (worker-util/post-message :notification
-                                     [[:div
-                                       [:p "Upload graph successfully"]]])
+             (p/resolve! d r))
            (catch :default e
            (catch :default e
              (worker-util/post-message :notification
              (worker-util/post-message :notification
                                        [[:div
                                        [[:div
                                          [:p "upload graph failed"]]
                                          [:p "upload graph failed"]]
                                         :error])
                                         :error])
-             (prn ::download-graph-failed e)
              (p/reject! d e)))))
              (p/reject! d e)))))
      d))
      d))
 
 
@@ -614,6 +610,37 @@
                                        :error])
                                        :error])
             (prn ::download-graph-failed e)))))))
             (prn ::download-graph-failed e)))))))
 
 
+  (rtc-request-download-graph
+   [this repo token graph-uuid]
+   (async-util/c->p
+    (async/go
+      (let [state (or @rtc-core/*state
+                      (<! (rtc-core/<init-state repo token false)))]
+        (<? (rtc-updown/<request-download-graph state graph-uuid))))))
+
+  (rtc-wait-download-graph-info-ready
+   [this repo token download-info-uuid graph-uuid timeout-ms]
+   (async-util/c->p
+    (async/go
+      (let [state (or @rtc-core/*state
+                      (<! (rtc-core/<init-state repo token false)))]
+        (ldb/write-transit-str
+         (<? (rtc-updown/<wait-download-info-ready state download-info-uuid graph-uuid timeout-ms)))))))
+
+  (rtc-download-graph-from-s3
+   [this graph-uuid graph-name s3-url]
+   (async-util/c->p
+    (async/go
+      (rtc-updown/<download-graph-from-s3 graph-uuid graph-name s3-url))))
+
+  (rtc-download-info-list
+   [this repo token graph-uuid]
+   (async-util/c->p
+    (async/go
+      (let [state (or @rtc-core/*state
+                      (<! (rtc-core/<init-state repo token false)))]
+        (<? (rtc-updown/<download-info-list state graph-uuid))))))
+
   (rtc-push-pending-ops
   (rtc-push-pending-ops
    [_this]
    [_this]
    (async/put! (:force-push-client-ops-chan @rtc-core/*state) true))
    (async/put! (:force-push-client-ops-chan @rtc-core/*state) true))

+ 7 - 7
src/main/frontend/extensions/pdf/assets.cljs

@@ -195,16 +195,16 @@
            (let [text       (:text content)
            (let [text       (:text content)
                  wrap-props #(if-let [stamp (:image content)]
                  wrap-props #(if-let [stamp (:image content)]
                                (assoc %
                                (assoc %
-                                      (pu/get-pid :hl-type) :area
-                                      (pu/get-pid :hl-stamp) stamp)
+                                      (pu/get-pid :logseq.property/hl-type) :area
+                                      (pu/get-pid :logseq.property/hl-stamp) stamp)
                                %)
                                %)
                  props (cond->
                  props (cond->
-                        {(pu/get-pid :ls-type)  :annotation
-                         (pu/get-pid :hl-page)  page
-                         (pu/get-pid :hl-color) (:color properties)}
+                        {(pu/get-pid :logseq.property/ls-type)  :annotation
+                         (pu/get-pid :logseq.property/hl-page)  page
+                         (pu/get-pid :logseq.property/hl-color) (:color properties)}
                          (not (config/db-based-graph? (state/get-current-repo)))
                          (not (config/db-based-graph? (state/get-current-repo)))
                        ;; force custom uuid
                        ;; force custom uuid
-                         (assoc (pu/get-pid :id) (str id)))
+                         (assoc :id (str id)))
                  properties (->>
                  properties (->>
                              (wrap-props props)
                              (wrap-props props)
                              (property-handler/replace-key-with-id (state/get-current-repo)))]
                              (property-handler/replace-key-with-id (state/get-current-repo)))]
@@ -237,7 +237,7 @@
         page-name (:block/original-name page)
         page-name (:block/original-name page)
         ;; FIXME: file-path property for db version
         ;; FIXME: file-path property for db version
         file-path (:file-path (:block/properties page))
         file-path (:file-path (:block/properties page))
-        hl-page   (pu/get-block-property-value block :hl-page)]
+        hl-page   (pu/get-block-property-value block :logseq.property/hl-page)]
     (when-let [target-key (and page-name (subs page-name 5))]
     (when-let [target-key (and page-name (subs page-name 5))]
       (p/let [hls (resolve-hls-data-by-key$ target-key)
       (p/let [hls (resolve-hls-data-by-key$ target-key)
               hls (and hls (:highlights hls))]
               hls (and hls (:highlights hls))]

+ 1 - 1
src/main/frontend/extensions/pdf/utils.cljs

@@ -17,7 +17,7 @@
   (and filename (string? filename) (string/starts-with? filename "hls__")))
   (and filename (string? filename) (string/starts-with? filename "hls__")))
 
 
 (def get-area-block-asset-url
 (def get-area-block-asset-url
-  #(publish-db/get-area-block-asset-url %1 %2 {:prop-lookup-fn pu/lookup}))
+  #(publish-db/get-area-block-asset-url %1 %2 {:prop-lookup-fn pu/lookup-by-name}))
 
 
 (defn get-bounding-rect
 (defn get-bounding-rect
   [rects]
   [rects]

+ 2 - 2
src/main/frontend/handler/block.cljs

@@ -116,7 +116,7 @@
   [block order-list-type]
   [block order-list-type]
   (let [order-block-fn? (fn [block]
   (let [order-block-fn? (fn [block]
                           (let [properties (:block/properties block)
                           (let [properties (:block/properties block)
-                                type (pu/lookup properties :logseq.order-list-type)]
+                                type (pu/lookup properties :logseq.property/order-list-type)]
                             (= type order-list-type)))
                             (= type order-list-type)))
         prev-block-fn   #(some->> (:db/id %) (db-model/get-prev-sibling (db/get-db)))
         prev-block-fn   #(some->> (:db/id %) (db-model/get-prev-sibling (db/get-db)))
         prev-block      (prev-block-fn block)]
         prev-block      (prev-block-fn block)]
@@ -145,7 +145,7 @@
 (defn attach-order-list-state
 (defn attach-order-list-state
   [config block]
   [config block]
   (let [properties (:block/properties block)
   (let [properties (:block/properties block)
-        type (pu/lookup properties :logseq.order-list-type)
+        type (pu/lookup properties :logseq.property/order-list-type)
         own-order-list-type  (some-> type str string/lower-case)
         own-order-list-type  (some-> type str string/lower-case)
         own-order-list-index (some->> own-order-list-type (get-idx-of-order-list-block block))]
         own-order-list-index (some->> own-order-list-type (get-idx-of-order-list-block block))]
     (assoc config :own-order-list-type own-order-list-type
     (assoc config :own-order-list-type own-order-list-type

+ 3 - 2
src/main/frontend/handler/db_based/editor.cljs

@@ -12,6 +12,7 @@
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.common.config-edn :as config-edn-common-handler]
             [frontend.handler.common.config-edn :as config-edn-common-handler]
             [frontend.handler.property :as property-handler]
             [frontend.handler.property :as property-handler]
+            [frontend.handler.property.util :as pu]
             [frontend.handler.repo-config :as repo-config-handler]
             [frontend.handler.repo-config :as repo-config-handler]
             [frontend.modules.outliner.ui :as ui-outliner-tx]
             [frontend.modules.outliner.ui :as ui-outliner-tx]
             [frontend.modules.outliner.op :as outliner-op]
             [frontend.modules.outliner.op :as outliner-op]
@@ -123,7 +124,7 @@
 (defn- set-heading-aux!
 (defn- set-heading-aux!
   [block-id heading]
   [block-id heading]
   (let [block (db/pull [:block/uuid block-id])
   (let [block (db/pull [:block/uuid block-id])
-        old-heading (:logseq.property/heading block)]
+        old-heading (pu/lookup (:block/properties block) :logseq.property/heading)]
     (cond
     (cond
       ;; nothing changed for first two cases
       ;; nothing changed for first two cases
       (or (and (nil? old-heading) (nil? heading))
       (or (and (nil? old-heading) (nil? heading))
@@ -162,4 +163,4 @@
    {:outliner-op :save-block}
    {:outliner-op :save-block}
    (doseq [block (keep #(set-heading-aux! % heading) block-ids)]
    (doseq [block (keep #(set-heading-aux! % heading) block-ids)]
      (outliner-op/save-block! block))
      (outliner-op/save-block! block))
-   (property-handler/batch-set-block-property! repo block-ids :logseq.property/heading heading)))
+   (property-handler/batch-set-block-property! repo block-ids :heading heading)))

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

@@ -410,20 +410,20 @@
                   [[f (:db/id block) :block/collapsed-properties (:db/id property)]]
                   [[f (:db/id block) :block/collapsed-properties (:db/id property)]]
                   {:outliner-op :save-block})))
                   {:outliner-op :save-block})))
 
 
-(defn- get-namespace-parents
+(defn- get-class-parents
   [tags]
   [tags]
   (let [tags' (filter (fn [tag] (contains? (:block/type tag) "class")) tags)
   (let [tags' (filter (fn [tag] (contains? (:block/type tag) "class")) tags)
-        *namespaces (atom #{})]
+        *classes (atom #{})]
     (doseq [tag tags']
     (doseq [tag tags']
-      (when-let [ns (:block/namespace tag)]
-        (loop [current-ns ns]
+      (when-let [parent (:class/parent tag)]
+        (loop [current-parent parent]
           (when (and
           (when (and
-                 current-ns
-                 (contains? (:block/type ns) "class")
-                 (not (contains? @*namespaces (:db/id ns))))
-            (swap! *namespaces conj current-ns)
-            (recur (:block/namespace current-ns))))))
-    @*namespaces))
+                 current-parent
+                 (contains? (:block/type parent) "class")
+                 (not (contains? @*classes (:db/id parent))))
+            (swap! *classes conj current-parent)
+            (recur (:class/parent current-parent))))))
+    @*classes))
 
 
 (defn get-block-classes-properties
 (defn get-block-classes-properties
   [eid]
   [eid]
@@ -431,8 +431,8 @@
         classes (->> (:block/tags block)
         classes (->> (:block/tags block)
                      (sort-by :block/name)
                      (sort-by :block/name)
                      (filter (fn [tag] (contains? (:block/type tag) "class"))))
                      (filter (fn [tag] (contains? (:block/type tag) "class"))))
-        namespace-parents (get-namespace-parents classes)
-        all-classes (->> (concat classes namespace-parents)
+        class-parents (get-class-parents classes)
+        all-classes (->> (concat classes class-parents)
                          (filter (fn [class]
                          (filter (fn [class]
                                    (seq (:class/schema.properties class)))))
                                    (seq (:class/schema.properties class)))))
         all-properties (-> (mapcat (fn [class]
         all-properties (-> (mapcat (fn [class]

+ 3 - 4
src/main/frontend/handler/db_based/property/util.cljs

@@ -13,10 +13,9 @@
 
 
 ;; FIXME: property no long has `:block/name` attribute
 ;; FIXME: property no long has `:block/name` attribute
 (defn get-built-in-property-uuid
 (defn get-built-in-property-uuid
-  "Get a built-in property's uuid given its name"
-  ([property-name] (get-built-in-property-uuid (state/get-current-repo) property-name))
-  ([repo property-name]
-   (:block/uuid (db-utils/entity repo [:block/name (name property-name)]))))
+  "Get a built-in property's uuid given its db-ident"
+  ([db-ident] (get-built-in-property-uuid (state/get-current-repo) db-ident))
+  ([repo db-ident] (:block/uuid (db-utils/entity repo db-ident))))
 
 
 ;; FIXME: property no long has `:block/name` attribute
 ;; FIXME: property no long has `:block/name` attribute
 (defn get-user-property-uuid
 (defn get-user-property-uuid

+ 33 - 12
src/main/frontend/handler/db_based/rtc.cljs

@@ -10,13 +10,14 @@
             [logseq.db.sqlite.common-db :as sqlite-common-db]
             [logseq.db.sqlite.common-db :as sqlite-common-db]
             [frontend.handler.notification :as notification]))
             [frontend.handler.notification :as notification]))
 
 
+
 (defn <rtc-create-graph!
 (defn <rtc-create-graph!
   [repo]
   [repo]
   (when-let [^js worker @state/*db-worker]
   (when-let [^js worker @state/*db-worker]
     (user-handler/<wrap-ensure-id&access-token
     (user-handler/<wrap-ensure-id&access-token
      (let [token (state/get-auth-id-token)
      (let [token (state/get-auth-id-token)
            repo-name (sqlite-common-db/sanitize-db-name repo)]
            repo-name (sqlite-common-db/sanitize-db-name repo)]
-       (.rtc-upload-graph worker repo token repo-name)))))
+       (.rtc-async-upload-graph worker repo token repo-name)))))
 
 
 (defn <rtc-delete-graph!
 (defn <rtc-delete-graph!
   [graph-uuid]
   [graph-uuid]
@@ -26,16 +27,25 @@
        (.rtc-delete-graph worker token graph-uuid)))))
        (.rtc-delete-graph worker token graph-uuid)))))
 
 
 (defn <rtc-download-graph!
 (defn <rtc-download-graph!
-  [repo graph-uuid]
+  [graph-name graph-uuid timeout-ms]
   (when-let [^js worker @state/*db-worker]
   (when-let [^js worker @state/*db-worker]
     (state/set-state! :rtc/downloading-graph-uuid graph-uuid)
     (state/set-state! :rtc/downloading-graph-uuid graph-uuid)
     (user-handler/<wrap-ensure-id&access-token
     (user-handler/<wrap-ensure-id&access-token
-     (let [token (state/get-auth-id-token)]
+     (p/let [token (state/get-auth-id-token)
+             download-info-uuid (.rtc-request-download-graph worker nil token graph-uuid)
+             result (.rtc-wait-download-graph-info-ready worker nil token download-info-uuid graph-uuid timeout-ms)
+             {:keys [_download-info-uuid
+                     download-info-s3-url
+                     _download-info-tx-instant
+                     _download-info-t
+                     _download-info-created-at]
+              :as result} (ldb/read-transit-str result)]
        (->
        (->
-        (.rtc-download-graph worker repo token graph-uuid)
+        (when (not= result :timeout)
+          (assert (some? download-info-s3-url) result)
+          (.rtc-download-graph-from-s3 worker graph-uuid graph-name download-info-s3-url))
         (p/finally
         (p/finally
-          (fn []
-            (state/set-state! :rtc/downloading-graph-uuid nil))))))))
+          #(state/set-state! :rtc/downloading-graph-uuid nil)))))))
 
 
 (defn <rtc-stop!
 (defn <rtc-stop!
   []
   []
@@ -43,18 +53,29 @@
     (.rtc-stop worker)))
     (.rtc-stop worker)))
 
 
 (defn <rtc-start!
 (defn <rtc-start!
-  [repo]
+  [repo & {:keys [retry] :or {retry 0}}]
   (when-let [^js worker @state/*db-worker]
   (when-let [^js worker @state/*db-worker]
     (when (ldb/get-graph-rtc-uuid (db/get-db repo))
     (when (ldb/get-graph-rtc-uuid (db/get-db repo))
       (user-handler/<wrap-ensure-id&access-token
       (user-handler/<wrap-ensure-id&access-token
         ;; TODO: `<rtc-stop!` can return a chan so that we can remove timeout
         ;; TODO: `<rtc-stop!` can return a chan so that we can remove timeout
        (<rtc-stop!)
        (<rtc-stop!)
        (let [token (state/get-auth-id-token)]
        (let [token (state/get-auth-id-token)]
-         (-> (.rtc-start worker repo token
-                         (state/sub [:ui/developer-mode?]))
-             (p/then (fn [result]
-                       (when (= "rtc-not-closed-yet" result)
-                         (js/setTimeout #(<rtc-start! repo) 200))))))))))
+         (p/let [result (.rtc-start worker repo token (state/sub [:ui/developer-mode?]))
+                 _ (case result
+                     "rtc-not-closed-yet"
+                     (js/setTimeout #(<rtc-start! repo) 200)
+                     ":graph-not-ready"
+                     (when (< retry 3)
+                       (let [delay (* 2000 (inc retry))]
+                         (prn "graph still creating, retry rtc-start in " delay "ms")
+                         (p/do! (p/delay delay)
+                                (<rtc-start! repo :retry (inc retry)))))
+
+                     (":break-rtc-loop" ":stop-rtc-loop")
+                     nil
+                     ;; else
+                     nil)]
+           nil))))))
 
 
 (defn <get-remote-graphs
 (defn <get-remote-graphs
   []
   []

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

@@ -85,7 +85,7 @@
 (defn get-block-own-order-list-type
 (defn get-block-own-order-list-type
   [block]
   [block]
   (let [properties (:block/properties block)]
   (let [properties (:block/properties block)]
-    (pu/lookup properties :logseq.order-list-type)))
+    (pu/lookup properties :logseq.property/order-list-type)))
 
 
 (defn set-block-own-order-list-type!
 (defn set-block-own-order-list-type!
   [block type]
   [block type]
@@ -892,7 +892,7 @@
 (defn set-block-query-properties!
 (defn set-block-query-properties!
   [block-id all-properties key add?]
   [block-id all-properties key add?]
   (when-let [block (db/entity [:block/uuid block-id])]
   (when-let [block (db/entity [:block/uuid block-id])]
-    (let [query-properties (:query-properties (:block/properties block))
+    (let [query-properties (:logseq.property/query-properties block)
           repo (state/get-current-repo)
           repo (state/get-current-repo)
           db-based? (config/db-based-graph? repo)
           db-based? (config/db-based-graph? repo)
           query-properties (if db-based?
           query-properties (if db-based?
@@ -3415,8 +3415,8 @@
   (->> (:block/macros (db/entity (:db/id block)))
   (->> (:block/macros (db/entity (:db/id block)))
        (some (fn [macro]
        (some (fn [macro]
                (let [properties (:block/properties macro)
                (let [properties (:block/properties macro)
-                     macro-name (pu/lookup properties :logseq.macro-name)
-                     macro-arguments (pu/lookup properties :logseq.macro-arguments)]
+                     macro-name (pu/lookup properties :logseq.property/macro-name)
+                     macro-arguments (pu/lookup properties :logseq.property/macro-arguments)]
                  (when-let [query-body (and (= "query" macro-name) (not-empty (string/join " " macro-arguments)))]
                  (when-let [query-body (and (= "query" macro-name) (not-empty (string/join " " macro-arguments)))]
                    (seq (:query
                    (seq (:query
                          (try
                          (try

+ 6 - 6
src/main/frontend/handler/events.cljs

@@ -73,7 +73,6 @@
             [frontend.util :as util]
             [frontend.util :as util]
             [frontend.util.persist-var :as persist-var]
             [frontend.util.persist-var :as persist-var]
             [goog.dom :as gdom]
             [goog.dom :as gdom]
-            [logseq.db.frontend.schema :as db-schema]
             [logseq.common.config :as common-config]
             [logseq.common.config :as common-config]
             [promesa.core :as p]
             [promesa.core :as p]
             [lambdaisland.glogi :as log]
             [lambdaisland.glogi :as log]
@@ -142,7 +141,6 @@
     (login/open-login-modal!)))
     (login/open-login-modal!)))
 
 
 (defmethod handle :graph/added [[_ repo {:keys [empty-graph?]}]]
 (defmethod handle :graph/added [[_ repo {:keys [empty-graph?]}]]
-  (db/set-key-value repo :ast/version db-schema/ast-version)
   (search-handler/rebuild-indices!)
   (search-handler/rebuild-indices!)
   (plugin-handler/hook-plugin-app :graph-after-indexed {:repo repo :empty-graph? empty-graph?})
   (plugin-handler/hook-plugin-app :graph-after-indexed {:repo repo :empty-graph? empty-graph?})
   (when (state/setups-picker?)
   (when (state/setups-picker?)
@@ -193,7 +191,8 @@
    (graph-switch graph)
    (graph-switch graph)
    (state/set-state! :sync-graph/init? false)
    (state/set-state! :sync-graph/init? false)
    (when (:rtc-download? opts)
    (when (:rtc-download? opts)
-     (and (search-handler/rebuild-indices!) true))))
+     (and (search-handler/rebuild-indices!) true)
+     (repo-handler/refresh-repos!))))
 
 
 (defmethod handle :graph/switch [[_ graph opts]]
 (defmethod handle :graph/switch [[_ graph opts]]
   (state/set-state! :db/async-queries #{})
   (state/set-state! :db/async-queries #{})
@@ -330,7 +329,7 @@
 
 
 (defmethod handle :modal/set-query-properties [[_ block all-properties]]
 (defmethod handle :modal/set-query-properties [[_ block all-properties]]
   (let [properties (:block/properties block)
   (let [properties (:block/properties block)
-        query-properties (pu/lookup properties :query-properties)
+        query-properties (pu/lookup properties :logseq.property/query-properties)
         block-properties (if (config/db-based-graph? (state/get-current-repo))
         block-properties (if (config/db-based-graph? (state/get-current-repo))
                            query-properties
                            query-properties
                            (some-> query-properties
                            (some-> query-properties
@@ -813,9 +812,10 @@
       (page-handler/ls-dir-files! st/refresh! opts'))))
       (page-handler/ls-dir-files! st/refresh! opts'))))
 
 
 (defmethod handle :graph/new-db-graph [[_ _opts]]
 (defmethod handle :graph/new-db-graph [[_ _opts]]
-  (state/set-modal!
+  (shui/dialog-open!
     repo/new-db-graph
     repo/new-db-graph
     {:id :new-db-graph
     {:id :new-db-graph
+     :title [:h2 "Create a new graph"]
      :label "graph-setup"}))
      :label "graph-setup"}))
 
 
 (defmethod handle :search/transact-data [[_ repo data]]
 (defmethod handle :search/transact-data [[_ repo data]]
@@ -977,7 +977,7 @@
 (defmethod handle :rtc/download-remote-graph [[_ graph-name graph-uuid]]
 (defmethod handle :rtc/download-remote-graph [[_ graph-name graph-uuid]]
   (->
   (->
    (p/do!
    (p/do!
-    (rtc-handler/<rtc-download-graph! graph-name graph-uuid))
+    (rtc-handler/<rtc-download-graph! graph-name graph-uuid 60000))
    (p/catch (fn [e]
    (p/catch (fn [e]
               (println "RTC download graph failed, error:")
               (println "RTC download graph failed, error:")
               (js/console.error e)))))
               (js/console.error e)))))

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

@@ -107,7 +107,7 @@
               (not journal?)
               (not journal?)
               (remove :block/journal?)
               (remove :block/journal?)
               (not excluded-pages?)
               (not excluded-pages?)
-              (remove (fn [p] (true? (pu/get-block-property-value p :exclude-from-graph-view)))))
+              (remove (fn [p] (true? (pu/get-block-property-value p :logseq.property/exclude-from-graph-view)))))
             links (concat (seq relation)
             links (concat (seq relation)
                           (seq tagged-pages)
                           (seq tagged-pages)
                           (seq namespaces))
                           (seq namespaces))

+ 2 - 3
src/main/frontend/handler/page.cljs

@@ -26,7 +26,6 @@
             [goog.functions :refer [debounce]]
             [goog.functions :refer [debounce]]
             [goog.object :as gobj]
             [goog.object :as gobj]
             [lambdaisland.glogi :as log]
             [lambdaisland.glogi :as log]
-            [logseq.db.frontend.property :as db-property]
             [logseq.common.config :as common-config]
             [logseq.common.config :as common-config]
             [logseq.common.util :as common-util]
             [logseq.common.util :as common-util]
             [logseq.common.util.page-ref :as page-ref]
             [logseq.common.util.page-ref :as page-ref]
@@ -234,14 +233,14 @@
                    (or (util/uuid-string? name)
                    (or (util/uuid-string? name)
                        (common-config/draw? name)
                        (common-config/draw? name)
                        (db/built-in-pages-names (string/upper-case name))
                        (db/built-in-pages-names (string/upper-case name))
-                       (db-property/built-in-properties-keys-str name)))))
+                       (and (contains? (set (:block/type p)) "property") (ldb/built-in? p))))))
        (common-handler/fix-pages-timestamps)))
        (common-handler/fix-pages-timestamps)))
 
 
 (defn get-filters
 (defn get-filters
   [page-name]
   [page-name]
   (let [properties (db/get-page-properties page-name)]
   (let [properties (db/get-page-properties page-name)]
     (if (config/db-based-graph? (state/get-current-repo))
     (if (config/db-based-graph? (state/get-current-repo))
-      (pu/lookup properties :filters)
+      (pu/lookup properties :logseq.property/filters)
       (let [properties-str (or (:filters properties) "{}")]
       (let [properties-str (or (:filters properties) "{}")]
         (try (reader/read-string properties-str)
         (try (reader/read-string properties-str)
              (catch :default e
              (catch :default e

+ 25 - 9
src/main/frontend/handler/property/util.cljs

@@ -4,34 +4,50 @@
   compatible with file graphs"
   compatible with file graphs"
   (:require [frontend.state :as state]
   (:require [frontend.state :as state]
             [frontend.db :as db]
             [frontend.db :as db]
+            [datascript.core :as d]
+            [logseq.db.sqlite.util :as sqlite-util]
             [logseq.db.frontend.property :as db-property]))
             [logseq.db.frontend.property :as db-property]))
 
 
 (defn lookup
 (defn lookup
-  "Get the value of coll's (a map) `key`. For file and db graphs"
+  "Get the value of coll's (a map) by db-ident. For file and db graphs"
   [coll key]
   [coll key]
   (let [repo (state/get-current-repo)
   (let [repo (state/get-current-repo)
         db (db/get-db repo)]
         db (db/get-db repo)]
     (db-property/lookup repo db coll key)))
     (db-property/lookup repo db coll key)))
 
 
+(defn lookup-by-name
+  "Get the value of coll's (a map) by name. Only use this
+   for file graphs or for db graphs when user properties are involved"
+  [coll key]
+  (let [repo (state/get-current-repo)
+        db (db/get-db repo)
+        property-name (if (keyword? key)
+                        (name key)
+                        key)]
+    (if (sqlite-util/db-based-graph? repo)
+      (when-let [property (d/entity db (db-property/get-db-ident-from-name property-name))]
+        (get coll (:block/uuid property)))
+      (get coll key))))
+
 (defn get-block-property-value
 (defn get-block-property-value
-  "Get the value of block's property `key`"
-  [block key]
+  "Get the value of a built-in block's property by its db-ident"
+  [block db-ident]
   (let [repo (state/get-current-repo)
   (let [repo (state/get-current-repo)
         db (db/get-db repo)]
         db (db/get-db repo)]
-    (db-property/get-block-property-value repo db block key)))
+    (db-property/get-block-property-value repo db block db-ident)))
 
 
 (defn get-pid
 (defn get-pid
-  "Get a property's id (name or uuid) given its name. For file and db graphs"
-  [property-name]
+  "Get a built-in property's id (db-ident or name) given its db-ident. For file and db graphs"
+  [db-ident]
   (let [repo (state/get-current-repo)
   (let [repo (state/get-current-repo)
         db (db/get-db repo)]
         db (db/get-db repo)]
-    (db-property/get-pid repo db property-name)))
+    (db-property/get-pid repo db db-ident)))
 
 
 (defn block->shape [block]
 (defn block->shape [block]
-  (get-block-property-value block :logseq.tldraw.shape))
+  (get-block-property-value block :logseq.property.tldraw/shape))
 
 
 (defn page-block->tldr-page [block]
 (defn page-block->tldr-page [block]
-  (get-block-property-value block :logseq.tldraw.page))
+  (get-block-property-value block :logseq.property.tldraw/page))
 
 
 (defn shape-block?
 (defn shape-block?
   [block]
   [block]

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

@@ -55,7 +55,7 @@
     (let [block (when (uuid? page-name-or-block-uuid)
     (let [block (when (uuid? page-name-or-block-uuid)
                   (model/get-block-by-uuid page-name-or-block-uuid))
                   (model/get-block-by-uuid page-name-or-block-uuid))
           properties (:block/properties block)]
           properties (:block/properties block)]
-      (if (pu/lookup properties :heading)
+      (if (pu/lookup properties :logseq.property/heading)
         {:to :page-block
         {:to :page-block
          :path-params {:name (get-in block [:block/page :block/name])
          :path-params {:name (get-in block [:block/page :block/name])
                        :block-route-name (model/heading-content->route-name (:block/content block))}}
                        :block-route-name (model/heading-content->route-name (:block/content block))}}

+ 7 - 9
src/main/frontend/handler/user.cljs

@@ -13,9 +13,7 @@
             [frontend.state :as state]
             [frontend.state :as state]
             [goog.crypt :as crypt]
             [goog.crypt :as crypt]
             [goog.crypt.Hmac]
             [goog.crypt.Hmac]
-            [goog.crypt.Sha256]
-            [logseq.db :as ldb]
-            [frontend.db :as db]))
+            [goog.crypt.Sha256]))
 
 
 (defn set-preferred-format!
 (defn set-preferred-format!
   [format]
   [format]
@@ -280,17 +278,17 @@
 
 
 (defn get-user-type
 (defn get-user-type
   [repo]
   [repo]
-  (when-let [uuid (ldb/get-graph-rtc-uuid (db/get-db repo))]
-    (-> (some #(when (= uuid (:GraphUUID %)) %) (:rtc/graphs @state/state))
-        :graph<->user-user-type)))
+  (-> (some #(when (= repo (:url %)) %) (:rtc/graphs @state/state))
+      :graph<->user-user-type))
 
 
 (defn manager?
 (defn manager?
   [repo]
   [repo]
   (= (get-user-type repo) "manager"))
   (= (get-user-type repo) "manager"))
 
 
-(defn member?
-  [repo]
-  (= (get-user-type repo) "member"))
+;; TODO: Remove if still unused
+#_(defn member?
+    [repo]
+    (= (get-user-type repo) "member"))
 
 
 (comment
 (comment
   ;; We probably need this for some new features later
   ;; We probably need this for some new features later

+ 10 - 10
src/main/frontend/handler/whiteboard.cljs

@@ -31,7 +31,7 @@
 
 
 (defn- build-shapes
 (defn- build-shapes
   [page-block blocks]
   [page-block blocks]
-  (let [page-metadata (pu/get-block-property-value page-block :logseq.tldraw.page)
+  (let [page-metadata (pu/get-block-property-value page-block :logseq.property.tldraw/page)
         shapes-index (:shapes-index page-metadata)
         shapes-index (:shapes-index page-metadata)
         shape-id->index (zipmap shapes-index (range 0 (count shapes-index)))]
         shape-id->index (zipmap shapes-index (range 0 (count shapes-index)))]
     (->> blocks
     (->> blocks
@@ -61,10 +61,10 @@
     {:block/original-name page-name
     {:block/original-name page-name
      :block/name (util/page-name-sanity-lc page-name)
      :block/name (util/page-name-sanity-lc page-name)
      :block/type "whiteboard"
      :block/type "whiteboard"
-     :block/properties {(pu/get-pid :ls-type)
+     :block/properties {(pu/get-pid :logseq.property/ls-type)
                         :whiteboard-page
                         :whiteboard-page
 
 
-                        (pu/get-pid :logseq.tldraw.page)
+                        (pu/get-pid :logseq.property.tldraw/page)
                         {:id (get-k "id")
                         {:id (get-k "id")
                          :name (get-k "name")
                          :name (get-k "name")
                          :bindings (js->clj-keywordize (get-k "bindings"))
                          :bindings (js->clj-keywordize (get-k "bindings"))
@@ -98,7 +98,7 @@
         repo (state/get-current-repo)
         repo (state/get-current-repo)
         deleted-shapes (when (seq deleted-ids)
         deleted-shapes (when (seq deleted-ids)
                          (->> (db/pull-many repo '[*] (mapv (fn [id] [:block/uuid (uuid id)]) deleted-ids))
                          (->> (db/pull-many repo '[*] (mapv (fn [id] [:block/uuid (uuid id)]) deleted-ids))
-                              (mapv (fn [b] (pu/get-block-property-value b :logseq.tldraw.shape)))
+                              (mapv (fn [b] (pu/get-block-property-value b :logseq.property.tldraw/shape)))
                               (remove nil?)))
                               (remove nil?)))
         deleted-shapes-tx (mapv (fn [id] [:db/retractEntity [:block/uuid (uuid id)]]) deleted-ids)
         deleted-shapes-tx (mapv (fn [id] [:db/retractEntity [:block/uuid (uuid id)]]) deleted-ids)
         upserted-blocks (->> (map #(shape->block % page-name) upsert-shapes)
         upserted-blocks (->> (map #(shape->block % page-name) upsert-shapes)
@@ -106,11 +106,11 @@
                                        (= (:nonce
                                        (= (:nonce
                                            (pu/get-block-property-value
                                            (pu/get-block-property-value
                                             (db/entity [:block/uuid (:block/uuid b)])
                                             (db/entity [:block/uuid (:block/uuid b)])
-                                            :logseq.tldraw.shape))
+                                            :logseq.property.tldraw/shape))
                                           (:nonce
                                           (:nonce
                                            (pu/get-block-property-value
                                            (pu/get-block-property-value
                                             b
                                             b
-                                            :logseq.tldraw.shape))))))
+                                            :logseq.property.tldraw/shape))))))
         page-entity (model/get-page page-name)
         page-entity (model/get-page page-name)
         page-block (build-page-block page-entity page-name tl-page assets shapes-index)]
         page-block (build-page-block page-entity page-name tl-page assets shapes-index)]
     (when (or (seq upserted-blocks)
     (when (or (seq upserted-blocks)
@@ -133,7 +133,7 @@
   (let [tl-page ^js (second (first (.-pages app)))
   (let [tl-page ^js (second (first (.-pages app)))
         shapes (.-shapes ^js tl-page)
         shapes (.-shapes ^js tl-page)
         page-block (model/get-page page-name)
         page-block (model/get-page page-name)
-        prev-page-metadata (pu/get-block-property-value page-block :logseq.tldraw.page)
+        prev-page-metadata (pu/get-block-property-value page-block :logseq.property.tldraw/page)
         prev-shapes-index (:shapes-index prev-page-metadata)
         prev-shapes-index (:shapes-index prev-page-metadata)
         shape-id->prev-index (zipmap prev-shapes-index (range (count prev-shapes-index)))
         shape-id->prev-index (zipmap prev-shapes-index (range (count prev-shapes-index)))
         new-id-nonces (set (map-indexed (fn [idx shape]
         new-id-nonces (set (map-indexed (fn [idx shape]
@@ -180,8 +180,8 @@
 
 
 (defn get-default-new-whiteboard-tx
 (defn get-default-new-whiteboard-tx
   [page-name id]
   [page-name id]
-  (let [properties {(pu/get-pid :ls-type) :whiteboard-page,
-                    (pu/get-pid :logseq.tldraw.page)
+  (let [properties {(pu/get-pid :logseq.property/ls-type) :whiteboard-page,
+                    (pu/get-pid :logseq.property.tldraw/page)
                     {:id (str id),
                     {:id (str id),
                      :name page-name,
                      :name page-name,
                      :ls-type :whiteboard-page,
                      :ls-type :whiteboard-page,
@@ -318,7 +318,7 @@
     (let [tl-page ^js (second (first (.-pages app)))]
     (let [tl-page ^js (second (first (.-pages app)))]
       (when tl-page
       (when tl-page
         (when-let [page (db/entity [:block/name page-name])]
         (when-let [page (db/entity [:block/name page-name])]
-         (let [page-metadata (pu/get-block-property-value page :logseq.tldraw.page)
+         (let [page-metadata (pu/get-block-property-value page :logseq.property.tldraw/page)
                shapes-index (:shapes-index page-metadata)]
                shapes-index (:shapes-index page-metadata)]
            (when (seq shapes-index)
            (when (seq shapes-index)
              (.updateShapesIndex tl-page (bean/->js shapes-index)))))))))
              (.updateShapesIndex tl-page (bean/->js shapes-index)))))))))

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

@@ -12,7 +12,6 @@
             [logseq.common.config :as common-config]
             [logseq.common.config :as common-config]
             [frontend.db.async :as db-async]
             [frontend.db.async :as db-async]
             [frontend.config :as config]
             [frontend.config :as config]
-            [logseq.db.frontend.property :as db-property]
             [frontend.handler.file-based.property.util :as property-util]
             [frontend.handler.file-based.property.util :as property-util]
             [cljs-bean.core :as bean]
             [cljs-bean.core :as bean]
             [frontend.db :as db]
             [frontend.db :as db]
@@ -73,12 +72,11 @@
   []
   []
   (when-let [repo (state/get-current-repo)]
   (when-let [repo (state/get-current-repo)]
     (let [hidden-props (if (config/db-based-graph? repo)
     (let [hidden-props (if (config/db-based-graph? repo)
-                        (set (map #(or (get-in db-property/built-in-properties [% :original-name])
-                                       (name %))
-                                  db-property/hidden-built-in-properties))
-                        (set (map name (property-util/hidden-properties))))]
-     (p/let [properties (db-async/<get-all-properties)]
-       (remove hidden-props properties)))))
+                         ;; no-op since already removed
+                         (constantly false)
+                         (set (map name (property-util/hidden-properties))))]
+      (p/let [properties (db-async/<get-all-property-names)]
+        (remove hidden-props properties)))))
 
 
 (defn property-search
 (defn property-search
   ([q]
   ([q]

+ 3 - 2
src/main/frontend/shui.cljs

@@ -11,13 +11,14 @@
     [logseq.shui.context :refer [make-context]]))
     [logseq.shui.context :refer [make-context]]))
 
 
 
 
-(def default-versions {:logseq.table.version 1})
+(def default-versions {:logseq.property.table/version 1})
 
 
 (defn get-shui-component-version
 (defn get-shui-component-version
   "Returns the version of the shui component, checking first
   "Returns the version of the shui component, checking first
   the block properties, then the global config, then the defaults."
   the block properties, then the global config, then the defaults."
   [component-name block-config]
   [component-name block-config]
-  (let [version-key (keyword (str "logseq." (name component-name) ".version"))]
+  (let [version-key (keyword (str "logseq.property." (name component-name))
+                             "version")]
     (js/parseFloat
     (js/parseFloat
       (or (pu/lookup (get-in block-config [:block :block/properties]) version-key)
       (or (pu/lookup (get-in block-config [:block :block/properties]) version-key)
           (get-in (state/get-config) [version-key])
           (get-in (state/get-config) [version-key])

+ 16 - 0
src/main/frontend/worker/rtc/const.cljs

@@ -169,6 +169,22 @@
       [:action :string]
       [:action :string]
       [:s3-key :string]
       [:s3-key :string]
       [:graph-name :string]]]
       [:graph-name :string]]]
+    ["upload-graph"
+     [:map
+      [:req-id :string]
+      [:action :string]
+      [:s3-key :string]
+      [:graph-name :string]]]
+    ["download-graph"
+     [:map
+      [:req-id :string]
+      [:action :string]
+      [:graph-uuid :string]]]
+    ["download-info-list"
+     [:map
+      [:req-id :string]
+      [:action :string]
+      [:graph-uuid :string]]]
     ["grant-access"
     ["grant-access"
      [:map
      [:map
       [:req-id :string]
       [:req-id :string]

+ 62 - 47
src/main/frontend/worker/rtc/core.cljs

@@ -53,24 +53,25 @@
 ;;; exceptions ================================================================
 ;;; exceptions ================================================================
 
 
 (def ex-break-rtc-loop (ex-info "break rtc loop" {:type ::break-rtc-loop}))
 (def ex-break-rtc-loop (ex-info "break rtc loop" {:type ::break-rtc-loop}))
+(def ex-graph-not-ready (ex-info "graph still creating" {:type ::graph-not-ready}))
 
 
 ;;; exceptions (ends)
 ;;; exceptions (ends)
 
 
 
 
 (def state-schema
 (def state-schema
   "
   "
-  | :*graph-uuid                      | atom of graph-uuid syncing now                           |
-  | :*repo                            | atom of repo name syncing now                            |
-  | :data-from-ws-chan                | channel for receive messages from server websocket       |
-  | :data-from-ws-pub                 | pub of :data-from-ws-chan, dispatch by :req-id           |
-  | :*stop-rtc-loop-chan              | atom of chan to stop <loop-for-rtc                       |
-  | :*ws                              | atom of websocket                                        |
-  | :*rtc-state                       | atom of state of current rtc progress                    |
-  | :toggle-auto-push-client-ops-chan | channel to toggle pushing client ops automatically       |
-  | :*auto-push-client-ops?           | atom to show if it's push client-ops automatically       |
-  | :force-push-client-ops-chan       | chan used to force push client-ops                       |
-  | :dev-mode?                        | when not nil, will update :block-update-log              |
-  | :block-update-log                 | map of block-uuid-> coll of local-op and remote-updates  |
+  | :*graph-uuid                      | atom of graph-uuid syncing now                          |
+  | :*repo                            | atom of repo name syncing now                           |
+  | :data-from-ws-chan                | channel for receive messages from server websocket      |
+  | :data-from-ws-pub                 | pub of :data-from-ws-chan, dispatch by :req-id          |
+  | :*stop-rtc-loop-chan              | atom of chan to stop <loop-for-rtc                      |
+  | :*ws                              | atom of websocket                                       |
+  | :*rtc-state                       | atom of state of current rtc progress                   |
+  | :toggle-auto-push-client-ops-chan | channel to toggle pushing client ops automatically      |
+  | :*auto-push-client-ops?           | atom to show if it's push client-ops automatically      |
+  | :force-push-client-ops-chan       | chan used to force push client-ops                      |
+  | :dev-mode?                        | when not nil, will update :block-update-log             |
+  | :block-update-log                 | map of block-uuid-> coll of local-op and remote-updates |
 "
 "
   [:map {:closed true}
   [:map {:closed true}
    [:*graph-uuid :any]
    [:*graph-uuid :any]
@@ -344,7 +345,7 @@
     (when-let [local-parent (d/entity db [:block/uuid first-remote-parent])]
     (when-let [local-parent (d/entity db [:block/uuid first-remote-parent])]
       (let [page-name (:block/name local-parent)
       (let [page-name (:block/name local-parent)
             properties* (transit/read transit-r properties)
             properties* (transit/read transit-r properties)
-            shape-property-id (db-property/get-pid repo db :logseq.tldraw.shape)
+            shape-property-id (db-property/get-pid repo db :logseq.property.tldraw/shape)
             shape (and (map? properties*)
             shape (and (map? properties*)
                        (get properties* shape-property-id))]
                        (get properties* shape-property-id))]
         (assert (some? page-name) local-parent)
         (assert (some? page-name) local-parent)
@@ -918,6 +919,11 @@
     (stop-rtc state)
     (stop-rtc state)
     (throw ex-break-rtc-loop)))
     (throw ex-break-rtc-loop)))
 
 
+(defmethod handle-remote-genernal-exception :graph-not-ready [_ state]
+  (stop-rtc-helper state)
+  (stop-rtc state)
+  (throw ex-graph-not-ready))
+
 
 
 (defmethod handle-remote-genernal-exception nil [resp & _]
 (defmethod handle-remote-genernal-exception nil [resp & _]
   (throw (ex-info "unknown exception from remote" {:resp resp})))
   (throw (ex-info "unknown exception from remote" {:resp resp})))
@@ -1005,7 +1011,8 @@
 (declare notify-main-thread)
 (declare notify-main-thread)
 
 
 (defn <loop-for-rtc
 (defn <loop-for-rtc
-  ":loop-started-ch used to notify that rtc-loop started"
+  ":loop-started-ch used to notify that rtc-loop started.
+  return `:stop-rtc-loop`, `:break-rtc-loop`, `:graph-not-ready`"
   [state graph-uuid repo conn date-formatter & {:keys [loop-started-ch token]}]
   [state graph-uuid repo conn date-formatter & {:keys [loop-started-ch token]}]
   {:pre [(state-validator state)
   {:pre [(state-validator state)
          (some? graph-uuid)
          (some? graph-uuid)
@@ -1027,49 +1034,54 @@
       (reset! (:*graph-uuid state) graph-uuid)
       (reset! (:*graph-uuid state) graph-uuid)
       (let [resp (<? (ws/<send&receive state {:action "register-graph-updates"
       (let [resp (<? (ws/<send&receive state {:action "register-graph-updates"
                                               :graph-uuid graph-uuid}))]
                                               :graph-uuid graph-uuid}))]
+
         (try
         (try
-          (when (:ex-data resp) (handle-remote-genernal-exception resp state))
+          (when (:ex-data resp)
+            (handle-remote-genernal-exception resp state))
           (async/sub data-from-ws-pub "push-updates" push-data-from-ws-ch)
           (async/sub data-from-ws-pub "push-updates" push-data-from-ws-ch)
           (when loop-started-ch (async/close! loop-started-ch))
           (when loop-started-ch (async/close! loop-started-ch))
           (<?
           (<?
            (go-try
            (go-try
-             (loop [push-client-ops-ch
-                    (make-push-client-ops-timeout-ch repo (not @*auto-push-client-ops?))]
-               (let [{:keys [push-data-from-ws client-op-update stop continue]}
-                     (async/alt!
-                       toggle-auto-push-client-ops-ch {:continue true}
-                       force-push-client-ops-ch {:client-op-update true}
-                       push-client-ops-ch ([v] (if (and @*auto-push-client-ops? (true? v))
-                                                 {:client-op-update true}
-                                                 {:continue true}))
-                       push-data-from-ws-ch ([v] {:push-data-from-ws v})
-                       stop-rtc-loop-chan {:stop true}
-                       :priority true)]
-                 (cond
-                   continue
-                   (recur (make-push-client-ops-timeout-ch repo (not @*auto-push-client-ops?)))
-
-                   push-data-from-ws
-                   (let [r (<! (<push-data-from-ws-handler state repo conn date-formatter push-data-from-ws))]
-                     (when (= r ::need-pull-remote-data)
+            (loop [push-client-ops-ch
+                   (make-push-client-ops-timeout-ch repo (not @*auto-push-client-ops?))]
+              (let [{:keys [push-data-from-ws client-op-update stop continue]}
+                    (async/alt!
+                      toggle-auto-push-client-ops-ch {:continue true}
+                      force-push-client-ops-ch {:client-op-update true}
+                      push-client-ops-ch ([v] (if (and @*auto-push-client-ops? (true? v))
+                                                {:client-op-update true}
+                                                {:continue true}))
+                      push-data-from-ws-ch ([v] {:push-data-from-ws v})
+                      stop-rtc-loop-chan {:stop true}
+                      :priority true)]
+                (cond
+                  continue
+                  (recur (make-push-client-ops-timeout-ch repo (not @*auto-push-client-ops?)))
+
+                  push-data-from-ws
+                  (let [r (<! (<push-data-from-ws-handler state repo conn date-formatter push-data-from-ws))]
+                    (when (= r ::need-pull-remote-data)
                        ;; trigger a force push, which can pull remote-diff-data from local-t to remote-t
                        ;; trigger a force push, which can pull remote-diff-data from local-t to remote-t
-                       (async/put! force-push-client-ops-ch true))
-                     (recur (make-push-client-ops-timeout-ch repo (not @*auto-push-client-ops?))))
+                      (async/put! force-push-client-ops-ch true))
+                    (recur (make-push-client-ops-timeout-ch repo (not @*auto-push-client-ops?))))
 
 
-                   client-op-update
+                  client-op-update
                    ;; FIXME: access token expired
                    ;; FIXME: access token expired
-                   (let [_ (<? (<client-op-update-handler state token))]
-                     (recur (make-push-client-ops-timeout-ch repo (not @*auto-push-client-ops?))))
+                  (let [_ (<? (<client-op-update-handler state token))]
+                    (recur (make-push-client-ops-timeout-ch repo (not @*auto-push-client-ops?))))
 
 
-                   stop
-                   (stop-rtc-helper state)
+                  stop
+                  (stop-rtc-helper state)
 
 
-                   :else
-                   nil)))))
+                  :else
+                  nil)))))
           (async/unsub data-from-ws-pub "push-updates" push-data-from-ws-ch)
           (async/unsub data-from-ws-pub "push-updates" push-data-from-ws-ch)
+          :stop-rtc-loop
           (catch :default e
           (catch :default e
             (case (:type (ex-data e))
             (case (:type (ex-data e))
-              ::break-rtc-loop (prn :break-rtc-loop)
+              ::break-rtc-loop
+              (do (prn :break-rtc-loop)
+                  :break-rtc-loop)
               ;; else
               ;; else
               (prn ::unknown-ex e))))))))
               (prn ::unknown-ex e))))))))
 
 
@@ -1162,6 +1174,8 @@
 
 
 
 
 ;; FIXME: token might be expired
 ;; FIXME: token might be expired
+;;; TODO: `repo` shouldn't be required when init-state.
+;;;       state isn't related to one repo, e.g. `<get-graphs` is user-scope api, not repo-scope
 (defn <init-state
 (defn <init-state
   [repo token reset-*state? & {:keys [dev-mode?]
   [repo token reset-*state? & {:keys [dev-mode?]
                                :or {dev-mode? false}}]
                                :or {dev-mode? false}}]
@@ -1189,9 +1203,10 @@
               _ (reset! asset-sync/*asset-sync-state state-for-asset-sync)
               _ (reset! asset-sync/*asset-sync-state state-for-asset-sync)
               config (worker-state/get-config repo)
               config (worker-state/get-config repo)
               c1 (<loop-for-rtc state graph-uuid repo conn (common-config/get-date-formatter config))
               c1 (<loop-for-rtc state graph-uuid repo conn (common-config/get-date-formatter config))
-              c2 (asset-sync/<loop-for-assets-sync state-for-asset-sync graph-uuid repo conn)]
-          (<! c1)
-          (<! c2)))
+              c2 (asset-sync/<loop-for-assets-sync state-for-asset-sync graph-uuid repo conn)
+              rtc-loop-result (<! c1)
+              _ (<! c2)]
+          (str rtc-loop-result)))
       (worker-util/post-message :notification
       (worker-util/post-message :notification
                                 [[:div
                                 [[:div
                                   [:p "RTC is not supported for this graph"]]
                                   [:p "RTC is not supported for this graph"]]

+ 79 - 14
src/main/frontend/worker/rtc/full_upload_download_graph.cljs

@@ -3,8 +3,9 @@
   - download remote graph"
   - download remote graph"
   (:require-macros [frontend.worker.rtc.macro :refer [with-sub-data-from-ws get-req-id get-result-ch]])
   (:require-macros [frontend.worker.rtc.macro :refer [with-sub-data-from-ws get-req-id get-result-ch]])
   (:require [cljs-http.client :as http]
   (:require [cljs-http.client :as http]
-            [cljs.core.async :as async :refer [<! go]]
+            [cljs.core.async :as async :refer [<! go go-loop]]
             [cljs.core.async.interop :refer [p->c]]
             [cljs.core.async.interop :refer [p->c]]
+            [clojure.string :as string]
             [cognitect.transit :as transit]
             [cognitect.transit :as transit]
             [datascript.core :as d]
             [datascript.core :as d]
             [frontend.worker.async-util :include-macros true :refer [<? go-try]]
             [frontend.worker.async-util :include-macros true :refer [<? go-try]]
@@ -12,12 +13,11 @@
             [frontend.worker.rtc.ws :as ws :refer [<send!]]
             [frontend.worker.rtc.ws :as ws :refer [<send!]]
             [frontend.worker.state :as worker-state]
             [frontend.worker.state :as worker-state]
             [frontend.worker.util :as worker-util]
             [frontend.worker.util :as worker-util]
+            [logseq.common.util.page-ref :as page-ref]
+            [logseq.db.frontend.content :as db-content]
             [logseq.db.frontend.schema :as db-schema]
             [logseq.db.frontend.schema :as db-schema]
             [logseq.outliner.core :as outliner-core]
             [logseq.outliner.core :as outliner-core]
-            [logseq.db.frontend.content :as db-content]
-            [promesa.core :as p]
-            [clojure.string :as string]
-            [logseq.common.util.page-ref :as page-ref]))
+            [promesa.core :as p]))
 
 
 (def transit-r (transit/reader :json))
 (def transit-r (transit/reader :json))
 
 
@@ -39,8 +39,7 @@
                     {:db/id (:e (first datoms))}
                     {:db/id (:e (first datoms))}
                     datoms)))))))
                     datoms)))))))
 
 
-(defn <upload-graph
-  "Upload current repo to remote, return remote {:req-id xxx :graph-uuid <new-remote-graph-uuid>}"
+(defn <async-upload-graph
   [state repo conn remote-graph-name]
   [state repo conn remote-graph-name]
   (go
   (go
     (let [{:keys [url key all-blocks-str]}
     (let [{:keys [url key all-blocks-str]}
@@ -50,21 +49,21 @@
                   all-blocks-str (transit/write (transit/writer :json) all-blocks)]
                   all-blocks-str (transit/write (transit/writer :json) all-blocks)]
               (merge (<! (get-result-ch)) {:all-blocks-str all-blocks-str})))]
               (merge (<! (get-result-ch)) {:all-blocks-str all-blocks-str})))]
       (<! (http/put url {:body all-blocks-str}))
       (<! (http/put url {:body all-blocks-str}))
-      (let [r (<? (ws/<send&receive state {:action "full-upload-graph"
+      (let [r (<? (ws/<send&receive state {:action "upload-graph"
                                            :s3-key key
                                            :s3-key key
                                            :graph-name remote-graph-name}))]
                                            :graph-name remote-graph-name}))]
         (if-not (:graph-uuid r)
         (if-not (:graph-uuid r)
           (ex-info "upload graph failed" r)
           (ex-info "upload graph failed" r)
           (let [^js worker-obj (:worker/object @worker-state/*state)]
           (let [^js worker-obj (:worker/object @worker-state/*state)]
             (d/transact! conn
             (d/transact! conn
-                         [{:db/ident :graph/uuid :graph/uuid (:graph-uuid r)}
-                          {:db/ident :graph/local-tx :graph/local-tx (:graph-uuid r)}])
+                         [{:db/ident :logseq.kv/graph-uuid :graph/uuid (:graph-uuid r)}
+                          {:db/ident :logseq.kv/graph-local-tx :graph/local-tx "0"}])
             (<! (p->c
             (<! (p->c
                  (p/do!
                  (p/do!
                   (.storeMetadata worker-obj repo (pr-str {:graph/uuid (:graph-uuid r)})))))
                   (.storeMetadata worker-obj repo (pr-str {:graph/uuid (:graph-uuid r)})))))
             (op-mem-layer/init-empty-ops-store! repo)
             (op-mem-layer/init-empty-ops-store! repo)
             (op-mem-layer/update-graph-uuid! repo (:graph-uuid r))
             (op-mem-layer/update-graph-uuid! repo (:graph-uuid r))
-            (op-mem-layer/update-local-tx! repo (:t r))
+            (op-mem-layer/update-local-tx! repo 8)
             (<! (op-mem-layer/<sync-to-idb-layer! repo))
             (<! (op-mem-layer/<sync-to-idb-layer! repo))
             r))))))
             r))))))
 
 
@@ -158,8 +157,9 @@
          blocks* (replace-db-id-with-temp-id blocks)
          blocks* (replace-db-id-with-temp-id blocks)
          blocks-with-page-id (fill-block-fields blocks*)
          blocks-with-page-id (fill-block-fields blocks*)
          tx-data (concat blocks-with-page-id
          tx-data (concat blocks-with-page-id
-                       [{:db/ident :graph/uuid :graph/uuid graph-uuid}])
+                         [{:db/ident :logseq.kv/graph-uuid :graph/uuid graph-uuid}])
          ^js worker-obj (:worker/object @worker-state/*state)
          ^js worker-obj (:worker/object @worker-state/*state)
+         _ (op-mem-layer/update-local-tx! repo t)
          work (p/do!
          work (p/do!
                (.createOrOpenDB worker-obj repo {:close-other-db? false})
                (.createOrOpenDB worker-obj repo {:close-other-db? false})
                (.exportDB worker-obj repo)
                (.exportDB worker-obj repo)
@@ -167,8 +167,7 @@
                (transact-block-refs! repo))]
                (transact-block-refs! repo))]
      (<? (p->c work))
      (<? (p->c work))
 
 
-     (worker-util/post-message :add-repo {:repo repo})
-     (op-mem-layer/update-local-tx! repo t))))
+     (worker-util/post-message :add-repo {:repo repo}))))
 
 
 (defn <download-graph
 (defn <download-graph
   [state repo graph-uuid]
   [state repo graph-uuid]
@@ -190,3 +189,69 @@
            (<! (op-mem-layer/<sync-to-idb-layer! repo))
            (<! (op-mem-layer/<sync-to-idb-layer! repo))
            (<! (p->c (.storeMetadata worker-obj repo (pr-str {:graph/uuid graph-uuid}))))
            (<! (p->c (.storeMetadata worker-obj repo (pr-str {:graph/uuid graph-uuid}))))
            (worker-state/set-rtc-downloading-graph! false)))))))
            (worker-state/set-rtc-downloading-graph! false)))))))
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; async download-graph ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defn <request-download-graph
+  [state graph-uuid]
+  (go-try
+   (let [{:keys [download-info-uuid]}
+         (<? (ws/<send&receive state {:action "download-graph"
+                                      :graph-uuid graph-uuid}))]
+     download-info-uuid)))
+
+
+(defn <wait-download-info-ready
+  [state download-info-uuid graph-uuid timeout-ms]
+  (let [init-interval 1000
+        interval      3000
+        timeout-ch    (async/timeout timeout-ms)]
+    (go-loop [interval-ch (async/timeout init-interval)]
+      (let [{:keys [timeout retry]}
+            (async/alt!
+              timeout-ch {:timeout true}
+              interval-ch {:retry true}
+              :priority true)]
+        (cond
+          timeout :timeout
+          retry
+          (let [{:keys [download-info-list]}
+                (<? (ws/<send&receive state {:action     "download-info-list"
+                                             :graph-uuid graph-uuid}))
+                finished-download-info
+                (some
+                 (fn [download-info]
+                   (when (and (= download-info-uuid (:download-info-uuid download-info))
+                              (:download-info-s3-url download-info))
+                     download-info))
+                 download-info-list)]
+            (if finished-download-info
+              finished-download-info
+              (recur (async/timeout interval)))))))))
+
+(defn <download-graph-from-s3
+  [graph-uuid graph-name s3-url]
+  (let [^js worker-obj              (:worker/object @worker-state/*state)]
+    (go-try
+     (let [{:keys [status body] :as r} (<! (http/get s3-url))
+           repo                        (str "logseq_db_" graph-name)]
+       (if (not= 200 status)
+         (ex-info "<download-graph failed" r)
+         (let [all-blocks (transit/read transit-r body)]
+           (worker-state/set-rtc-downloading-graph! true)
+           (op-mem-layer/init-empty-ops-store! repo)
+           (<? (<transact-remote-all-blocks-to-sqlite all-blocks repo graph-uuid))
+           (op-mem-layer/update-graph-uuid! repo graph-uuid)
+           (<! (op-mem-layer/<sync-to-idb-layer! repo))
+           (<! (p->c (.storeMetadata worker-obj repo (pr-str {:graph/uuid graph-uuid}))))
+           (worker-state/set-rtc-downloading-graph! false)))))))
+
+(defn <download-info-list
+  [state graph-uuid]
+  (go-try
+    (<? (ws/<send&receive state {:action "download-info-list"
+                                 :graph-uuid graph-uuid}))))

+ 1 - 2
src/main/logseq/api.cljs

@@ -801,8 +801,7 @@
     (p/let [block-uuid (sdk-utils/uuid-or-throw-error block-uuid)
     (p/let [block-uuid (sdk-utils/uuid-or-throw-error block-uuid)
             _ (db-async/<get-block (state/get-current-repo) block-uuid :children? false)]
             _ (db-async/<get-block (state/get-current-repo) block-uuid :children? false)]
       (when-let [block (db-model/query-block-by-uuid block-uuid)]
       (when-let [block (db-model/query-block-by-uuid block-uuid)]
-        (let [property-id (pu/get-pid key)]
-          (get (:block/properties block) (if (string? property-id) (keyword property-id) property-id)))))))
+        (pu/lookup-by-name (:block/properties block) key)))))
 
 
 (def ^:export get_block_properties
 (def ^:export get_block_properties
   (fn [block-uuid]
   (fn [block-uuid]

+ 5 - 5
src/test/frontend/db/db_based_model_test.cljs

@@ -63,7 +63,7 @@
       ;; set class2's parent to class1
       ;; set class2's parent to class1
         (let [class2 (db/entity [:block/name "class2"])]
         (let [class2 (db/entity [:block/name "class2"])]
           (db/transact! [{:db/id (:db/id class2)
           (db/transact! [{:db/id (:db/id class2)
-                          :block/namespace (:db/id class)}]))
+                          :class/parent (:db/id class)}]))
         (test-helper/save-block! repo sbid "Block 2" {:tags ["class2"]})
         (test-helper/save-block! repo sbid "Block 2" {:tags ["class2"]})
         (is (= (model/get-class-objects repo (:db/id class))
         (is (= (model/get-class-objects repo (:db/id class))
                [(:db/id (db/entity [:block/uuid fbid]))
                [(:db/id (db/entity [:block/uuid fbid]))
@@ -99,7 +99,7 @@
     (is (false? (model/hidden-page? "$$$test")))
     (is (false? (model/hidden-page? "$$$test")))
     (is (true? (model/hidden-page? (str "$$$" (random-uuid)))))))
     (is (true? (model/hidden-page? (str "$$$" (random-uuid)))))))
 
 
-(deftest get-namespace-children-test
+(deftest get-class-children-test
   (let [opts {:redirect? false :create-first-block? false :class? true}
   (let [opts {:redirect? false :create-first-block? false :class? true}
         _ (page-handler/create! "class1" opts)
         _ (page-handler/create! "class1" opts)
         _ (page-handler/create! "class2" opts)
         _ (page-handler/create! "class2" opts)
@@ -108,9 +108,9 @@
         class2 (db/entity [:block/name "class2"])
         class2 (db/entity [:block/name "class2"])
         class3 (db/entity [:block/name "class3"])
         class3 (db/entity [:block/name "class3"])
         _ (db/transact! [{:db/id (:db/id class2)
         _ (db/transact! [{:db/id (:db/id class2)
-                          :block/namespace (:db/id class1)}
+                          :class/parent (:db/id class1)}
                          {:db/id (:db/id class3)
                          {:db/id (:db/id class3)
-                          :block/namespace (:db/id class2)}])]
+                          :class/parent (:db/id class2)}])]
     (is
     (is
-     (= (model/get-namespace-children repo (:db/id (db/entity [:block/name "class1"])))
+     (= (model/get-class-children repo (:db/id (db/entity [:block/name "class1"])))
         [(:db/id class2) (:db/id class3)]))))
         [(:db/id class2) (:db/id class3)]))))

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

@@ -4,7 +4,6 @@
             [clojure.test :refer [deftest is testing are use-fixtures]]
             [clojure.test :refer [deftest is testing are use-fixtures]]
             [frontend.test.helper :as test-helper]
             [frontend.test.helper :as test-helper]
             [datascript.core :as d]
             [datascript.core :as d]
-            [frontend.handler.property.util :as pu]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.handler.page :as page-handler]
             [frontend.handler.page :as page-handler]
             [frontend.handler.editor :as editor-handler]))
             [frontend.handler.editor :as editor-handler]))
@@ -153,9 +152,9 @@
       (let [fb (db/entity [:block/uuid fbid])
       (let [fb (db/entity [:block/uuid fbid])
             sb (db/entity [:block/uuid sbid])]
             sb (db/entity [:block/uuid sbid])]
         (are [x y] (= x y)
         (are [x y] (= x y)
-          (pu/get-block-property-value fb k)
+          (get (:block/properties fb) (:block/uuid (db/entity [:block/name k])))
           v
           v
-          (pu/get-block-property-value sb k)
+          (get (:block/properties sb) (:block/uuid (db/entity [:block/name k])))
           v))))
           v))))
 
 
   (testing "Batch remove properties"
   (testing "Batch remove properties"
@@ -214,7 +213,7 @@
       ;; set c2 as parent of c3
       ;; set c2 as parent of c3
       (let [c3 (db/entity [:block/name "class3"])]
       (let [c3 (db/entity [:block/name "class3"])]
         (db/transact! [{:db/id (:db/id c3)
         (db/transact! [{:db/id (:db/id c3)
-                        :block/namespace (:db/id c2)}]))
+                        :class/parent (:db/id c2)}]))
       (db-property-handler/class-add-property! repo c2id "property-3")
       (db-property-handler/class-add-property! repo c2id "property-3")
       (db-property-handler/class-add-property! repo c2id "property-4")
       (db-property-handler/class-add-property! repo c2id "property-4")
       (is (= 3 (count (:classes-properties
       (is (= 3 (count (:classes-properties

+ 31 - 1
src/test/frontend/worker/rtc/rtc_fns_test.cljs

@@ -405,7 +405,8 @@ server: ;; remove 2
   (let [repo (state/get-current-repo)
   (let [repo (state/get-current-repo)
         conn (conn/get-db repo false)
         conn (conn/get-db repo false)
         date-formatter (common-config/get-date-formatter (worker-state/get-config repo))
         date-formatter (common-config/get-date-formatter (worker-state/get-config repo))
-        [page1-uuid] (repeatedly random-uuid)]
+        [page1-uuid ;; page2-uuid page3-uuid page4-uuid
+         ] (repeatedly random-uuid)]
     (testing "apply-remote-update-page-ops-test1"
     (testing "apply-remote-update-page-ops-test1"
       (let [data-from-ws {:req-id "req-id" :t 1 :t-before 0
       (let [data-from-ws {:req-id "req-id" :t 1 :t-before 0
                           :affected-blocks
                           :affected-blocks
@@ -434,6 +435,35 @@ server: ;; remove 2
         (rtc-core/apply-remote-update-page-ops repo conn date-formatter update-page-ops)
         (rtc-core/apply-remote-update-page-ops repo conn date-formatter update-page-ops)
         (is (= (str page1-uuid "-rename") (:block/name (d/entity @conn [:block/uuid page1-uuid]))))))
         (is (= (str page1-uuid "-rename") (:block/name (d/entity @conn [:block/uuid page1-uuid]))))))
 
 
+    ;; TODO: add this test back when fixed
+    ;; (testing "apply-remote-update-page-ops-test3: create namespace-page"
+    ;;   (let [data-from-ws {:req-id "req-id" :t 1 :t-before 0
+    ;;                       :affected-blocks
+    ;;                       {page2-uuid {:op :update-page
+    ;;                                    :self page2-uuid
+    ;;                                    :page-name "aaa/bbb/ccc"
+    ;;                                    :original-name "aaa/bbb/ccc"}
+    ;;                        page3-uuid {:op :update-page
+    ;;                                    :self page3-uuid
+    ;;                                    :page-name "aaa/bbb"
+    ;;                                    :original-name "aaa/bbb"}
+    ;;                        page4-uuid {:op :update-page
+    ;;                                    :self page4-uuid
+    ;;                                    :page-name "aaa"
+    ;;                                    :original-name "aaa"}}}
+    ;;         update-page-ops (vals
+    ;;                          (:update-page-ops-map
+    ;;                           (#'rtc-core/affected-blocks->diff-type-ops repo (:affected-blocks data-from-ws))))]
+    ;;     (is (rtc-const/data-from-ws-validator data-from-ws))
+    ;;     (rtc-core/apply-remote-update-page-ops repo conn date-formatter update-page-ops)
+    ;;     (prn ::x
+    ;;          (into {} (d/entity @conn [:block/uuid page2-uuid]))
+    ;;          (into {} (d/entity @conn [:block/uuid page3-uuid]))
+    ;;          (into {} (d/entity @conn [:block/uuid page4-uuid]))
+    ;;          (into {} (d/entity @conn [:block/name "aaa"]))
+    ;;          (into {} (d/entity @conn [:block/name "aaa/bbb"]))
+    ;;          (into {} (d/entity @conn [:block/name "aaa/bbb/ccc"])))
+    ;;     ))
     (testing "apply-remote-remove-page-ops-test1"
     (testing "apply-remote-remove-page-ops-test1"
       (let [data-from-ws {:req-id "req-id" :t 1 :t-before 0
       (let [data-from-ws {:req-id "req-id" :t 1 :t-before 0
                           :affected-blocks
                           :affected-blocks

Різницю між файлами не показано, бо вона завелика
+ 353 - 317
static/yarn.lock


+ 4 - 9
yarn.lock

@@ -932,11 +932,6 @@
   dependencies:
   dependencies:
     mini-svg-data-uri "^1.2.3"
     mini-svg-data-uri "^1.2.3"
 
 
-"@tailwindcss/[email protected]":
-  version "0.4.2"
-  resolved "https://registry.yarnpkg.com/@tailwindcss/line-clamp/-/line-clamp-0.4.2.tgz#f353c5a8ab2c939c6267ac5b907f012e5ee130f9"
-  integrity sha512-HFzAQuqYCjyy/SX9sLGB1lroPzmcnWv1FHkIpmypte10hptf4oPUfucryMKovZh2u0uiS9U5Ty3GghWfEJGwVw==
-
 "@tailwindcss/[email protected]":
 "@tailwindcss/[email protected]":
   version "0.5.7"
   version "0.5.7"
   resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.7.tgz#e0b95bea787ee14c5a34a74fc824e6fe86ea8855"
   resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.7.tgz#e0b95bea787ee14c5a34a74fc824e6fe86ea8855"
@@ -4530,10 +4525,10 @@ [email protected]:
   resolved "https://registry.yarnpkg.com/just-once/-/just-once-1.1.0.tgz#fe81a185ebaeeb0947a7e705bf01cb6808db0ad8"
   resolved "https://registry.yarnpkg.com/just-once/-/just-once-1.1.0.tgz#fe81a185ebaeeb0947a7e705bf01cb6808db0ad8"
   integrity sha512-+rZVpl+6VyTilK7vB/svlMPil4pxqIJZkbnN7DKZTOzyXfun6ZiFeq2Pk4EtCEHZ0VU4EkdFzG8ZK5F3PErcDw==
   integrity sha512-+rZVpl+6VyTilK7vB/svlMPil4pxqIJZkbnN7DKZTOzyXfun6ZiFeq2Pk4EtCEHZ0VU4EkdFzG8ZK5F3PErcDw==
 
 
-katex@^0.16.7:
-  version "0.16.8"
-  resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.8.tgz#89b453f40e8557f423f31a1009e9298dd99d5ceb"
-  integrity sha512-ftuDnJbcbOckGY11OO+zg3OofESlbR5DRl2cmN8HeWeeFIV7wTXvAOx8kEjZjobhA+9wh2fbKeO6cdcA9Mnovg==
+katex@^0.16.10:
+  version "0.16.10"
+  resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.10.tgz#6f81b71ac37ff4ec7556861160f53bc5f058b185"
+  integrity sha512-ZiqaC04tp2O5utMsl2TEZTXxa6WSC4yo0fv5ML++D3QZv/vx2Mct0mTlRx3O+uUkjfuAgOkzsCmq5MiUEsDDdA==
   dependencies:
   dependencies:
     commander "^8.3.0"
     commander "^8.3.0"
 
 

Деякі файли не було показано, через те що забагато файлів було змінено