Browse Source

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

Konstantinos Kaloutas 1 year ago
parent
commit
8a91a400e5

+ 1 - 12
deps/db/src/logseq/db/frontend/property/util.cljs

@@ -47,16 +47,6 @@
         (assoc :block/type #{"hidden"}
         (assoc :block/type #{"hidden"}
                :block/format :markdown))))
                :block/format :markdown))))
 
 
-(defn new-property-tx
-  "Provide attributes for a new built-in property given name, schema and uuid.
-   TODO: Merge this with sqlite-util/build-new-property once common-util/page-name-sanity-lc
-   is available to deps/db"
-  [prop-name prop-schema prop-uuid]
-  {:block/uuid prop-uuid
-   :block/schema (merge {:type :default} prop-schema)
-   :block/original-name (name prop-name)
-   :block/name (common-util/page-name-sanity-lc (name prop-name))})
-
 (defn build-closed-values
 (defn build-closed-values
   "Builds all the tx needed for property with closed values including
   "Builds all the tx needed for property with closed values including
    the hidden page and closed value blocks as needed"
    the hidden page and closed value blocks as needed"
@@ -76,8 +66,7 @@
                (:closed-values property)))
                (:closed-values property)))
         property-schema (assoc (:block/schema property)
         property-schema (assoc (:block/schema property)
                                :values (mapv :block/uuid closed-value-blocks-tx))
                                :values (mapv :block/uuid closed-value-blocks-tx))
-        property-tx (merge (sqlite-util/build-new-property
-                            (new-property-tx prop-name property-schema (:block/uuid property)))
+        property-tx (merge (sqlite-util/build-new-property prop-name property-schema (:block/uuid property))
                            property-attributes)]
                            property-attributes)]
     (into [property-tx page-tx]
     (into [property-tx page-tx]
           (when-not closed-value-page-uuids? closed-value-blocks-tx))))
           (when-not closed-value-page-uuids? closed-value-blocks-tx))))

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

@@ -22,10 +22,9 @@
             {:block/schema schema :block/uuid (d/squuid) :closed-values closed-values}
             {:block/schema schema :block/uuid (d/squuid) :closed-values closed-values}
             {:icon-id (get default-property-uuids :icon)})
             {:icon-id (get default-property-uuids :icon)})
            [(sqlite-util/build-new-property
            [(sqlite-util/build-new-property
-             {:block/schema schema
-              :block/original-name (or original-name k-name)
-              :block/name (common-util/page-name-sanity-lc k-name)
-              :block/uuid (get default-property-uuids k-keyword (d/squuid))})])))
+             (or original-name k-name)
+             schema
+             (get default-property-uuids k-keyword (d/squuid)))])))
      db-property/built-in-properties)))
      db-property/built-in-properties)))
 
 
 (defn build-db-initial-data
 (defn build-db-initial-data

+ 8 - 5
deps/db/src/logseq/db/sqlite/util.cljs

@@ -35,12 +35,15 @@
 
 
 (defn build-new-property
 (defn build-new-property
   "Build a standard new property so that it is is consistent across contexts"
   "Build a standard new property so that it is is consistent across contexts"
-  [block]
+  [prop-name prop-schema prop-uuid]
   (block-with-timestamps
   (block-with-timestamps
-   (merge {:block/type "property"
-           :block/journal? false
-           :block/format :markdown}
-          block)))
+   {:block/type "property"
+    :block/journal? false
+    :block/format :markdown
+    :block/uuid prop-uuid
+    :block/schema (merge {:type :default} prop-schema)
+    :block/original-name (name prop-name)
+    :block/name (common-util/page-name-sanity-lc (name prop-name))}))
 
 
 
 
 (defn build-new-class
 (defn build-new-class

+ 14 - 13
deps/outliner/src/logseq/outliner/core.cljs

@@ -352,18 +352,18 @@
           eid (or db-id (when block-uuid [:block/uuid block-uuid]))
           eid (or db-id (when block-uuid [:block/uuid block-uuid]))
           block-entity (d/entity db eid)
           block-entity (d/entity db eid)
           m' (if (and (:block/content m) db-based?)
           m' (if (and (:block/content m) db-based?)
-              (update m :block/content
-                      (fn [content]
-                        (db-content/content-without-tags
-                         content
-                         (->>
-                          (map
-                           (fn [tag]
-                             (when (:block/uuid tag)
-                               (str db-content/page-ref-special-chars (:block/uuid tag))))
-                           (:block/tags m))
-                          (remove nil?)))))
-              m)
+               (update m :block/content
+                       (fn [content]
+                         (db-content/content-without-tags
+                          content
+                          (->>
+                           (map
+                            (fn [tag]
+                              (when (:block/uuid tag)
+                                (str db-content/page-ref-special-chars (:block/uuid tag))))
+                            (:block/tags m))
+                           (remove nil?)))))
+               m)
           m (cond->> m'
           m (cond->> m'
               db-based?
               db-based?
               (db-marker-handle conn))
               (db-marker-handle conn))
@@ -394,7 +394,8 @@
         ;; Remove macros as they are replaced by new ones
         ;; Remove macros as they are replaced by new ones
         (remove-macros-when-save db txs-state block-entity)
         (remove-macros-when-save db txs-state block-entity)
         ;; Remove orphaned refs from block
         ;; Remove orphaned refs from block
-        (remove-orphaned-refs-when-save @conn txs-state block-entity m))
+        (when (and (:block/content m) (not= (:block/content m) (:block/content block-entity)))
+          (remove-orphaned-refs-when-save @conn txs-state block-entity m)))
 
 
       ;; handle others txs
       ;; handle others txs
       (let [other-tx (:db/other-tx m)]
       (let [other-tx (:db/other-tx m)]

+ 1 - 1
package.json

@@ -101,7 +101,7 @@
         "@excalidraw/excalidraw": "0.16.1",
         "@excalidraw/excalidraw": "0.16.1",
         "@highlightjs/cdn-assets": "10.4.1",
         "@highlightjs/cdn-assets": "10.4.1",
         "@isomorphic-git/lightning-fs": "^4.6.0",
         "@isomorphic-git/lightning-fs": "^4.6.0",
-        "@logseq/capacitor-file-sync": "5.0.1",
+        "@logseq/capacitor-file-sync": "5.0.2",
         "@logseq/diff-merge": "0.2.2",
         "@logseq/diff-merge": "0.2.2",
         "@logseq/react-tweet-embed": "1.3.1-1",
         "@logseq/react-tweet-embed": "1.3.1-1",
         "@logseq/sqlite-wasm": "=0.1.0",
         "@logseq/sqlite-wasm": "=0.1.0",

+ 7 - 7
scripts/src/logseq/tasks/db_graph/create_graph.cljs

@@ -176,13 +176,13 @@
                                   :property-attributes
                                   :property-attributes
                                   {:db/id (or (property-db-ids (name prop-name))
                                   {:db/id (or (property-db-ids (name prop-name))
                                               (throw (ex-info "No :db/id for property" {:property prop-name})))}})
                                               (throw (ex-info "No :db/id for property" {:property prop-name})))}})
-                                [(sqlite-util/build-new-property
-                                  (merge (db-property-util/new-property-tx prop-name (get-in properties [prop-name :block/schema]) uuid)
-                                         {:db/id (or (property-db-ids (name prop-name))
-                                                     (throw (ex-info "No :db/id for property" {:property prop-name})))}
-                                         (when-let [props (not-empty (get-in properties [prop-name :properties]))]
-                                           {:block/properties (->block-properties-tx props uuid-maps)
-                                            :block/refs (build-property-refs props property-db-ids)})))]))
+                                [(merge
+                                  (sqlite-util/build-new-property prop-name (get-in properties [prop-name :block/schema]) uuid)
+                                  {:db/id (or (property-db-ids (name prop-name))
+                                                      (throw (ex-info "No :db/id for property" {:property prop-name})))}
+                                  (when-let [props (not-empty (get-in properties [prop-name :properties]))]
+                                            {:block/properties (->block-properties-tx props uuid-maps)
+                                             :block/refs (build-property-refs props property-db-ids)}))]))
                             property-uuids))
                             property-uuids))
         pages-and-blocks-tx
         pages-and-blocks-tx
         (vec
         (vec

+ 118 - 38
scripts/src/logseq/tasks/db_graph/create_graph_with_schema_org.cljs

@@ -33,20 +33,20 @@
       (throw (ex-info (str "No :block/uuid for " class-id) {}))))
       (throw (ex-info (str "No :block/uuid for " class-id) {}))))
 
 
 (defn- get-comment-string
 (defn- get-comment-string
-  [rdfs-comment renamed-classes]
+  [rdfs-comment renamed-pages]
   (let [desc* (if (map? rdfs-comment)
   (let [desc* (if (map? rdfs-comment)
                 (get rdfs-comment "@value")
                 (get rdfs-comment "@value")
                 rdfs-comment)
                 rdfs-comment)
         ;; Update refs to renamed classes
         ;; Update refs to renamed classes
-        regex (re-pattern (str "\\[\\[(" (string/join "|" (keys renamed-classes)) ")\\]\\]"))
-        desc (string/replace desc* regex #(str "[[" (get renamed-classes (second %)) "]]"))]
+        regex (re-pattern (str "\\[\\[(" (string/join "|" (keys renamed-pages)) ")\\]\\]"))
+        desc (string/replace desc* regex #(str "[[" (get renamed-pages (second %)) "]]"))]
     ;; Fix markdown and html links to schema website docs
     ;; Fix markdown and html links to schema website docs
     (string/replace desc #"(\(|\")/docs" "$1https://schema.org/docs")))
     (string/replace desc #"(\(|\")/docs" "$1https://schema.org/docs")))
 
 
 (defn- strip-schema-prefix [s]
 (defn- strip-schema-prefix [s]
   (string/replace-first s "schema:" ""))
   (string/replace-first s "schema:" ""))
 
 
-(defn- ->class-page [class-m class-db-ids class-uuids class-properties property-uuids {:keys [verbose renamed-classes]}]
+(defn- ->class-page [class-m class-db-ids class-uuids class-properties property-uuids {:keys [verbose renamed-classes renamed-pages]}]
   (let [parent-class* (class-m "rdfs:subClassOf")
   (let [parent-class* (class-m "rdfs:subClassOf")
         parent-class (cond
         parent-class (cond
                        (map? parent-class*)
                        (map? parent-class*)
@@ -73,7 +73,7 @@
              :db/id (get-class-db-id class-db-ids (class-m "@id"))
              :db/id (get-class-db-id class-db-ids (class-m "@id"))
              :properties (cond-> {:url url}
              :properties (cond-> {:url url}
                            (class-m "rdfs:comment")
                            (class-m "rdfs:comment")
-                           (assoc :description (get-comment-string (class-m "rdfs:comment") renamed-classes)))}
+                           (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 :block/namespace {:db/id (get-class-db-id class-db-ids parent-class)})
       (seq properties)
       (seq properties)
@@ -105,7 +105,7 @@
              (when (class-map %) :page))
              (when (class-map %) :page))
         range-includes))
         range-includes))
 
 
-(defn- ->property-page [property-m prop-uuid class-map class-uuids {:keys [verbose renamed-classes]}]
+(defn- ->property-page [property-m prop-uuid class-map class-uuids {:keys [verbose renamed-pages renamed-properties]}]
   (let [range-includes (get-range-includes property-m)
   (let [range-includes (get-range-includes property-m)
         schema-type (get-schema-type range-includes class-map)
         schema-type (get-schema-type range-includes class-map)
         ;; Pick first range to determine type as only one range is supported currently
         ;; Pick first range to determine type as only one range is supported currently
@@ -113,12 +113,15 @@
             (println "Picked property type:"
             (println "Picked property type:"
                      {:property (property-m "@id") :type schema-type :range-includes (vec range-includes)}))
                      {:property (property-m "@id") :type schema-type :range-includes (vec range-includes)}))
         _ (assert schema-type (str "No schema found for property " (property-m "@id")))
         _ (assert schema-type (str "No schema found for property " (property-m "@id")))
+        inverted-renamed-properties (set/map-invert renamed-properties)
+        class-name (strip-schema-prefix (property-m "@id"))
+        url (str "https://schema.org/" (get inverted-renamed-properties class-name class-name))
         schema (cond-> {:type schema-type}
         schema (cond-> {:type schema-type}
                  ;; This cardinality rule should be adjusted as we use schema.org more
                  ;; This cardinality rule should be adjusted as we use schema.org more
                  (= schema-type :page)
                  (= schema-type :page)
                  (assoc :cardinality :many)
                  (assoc :cardinality :many)
                  (property-m "rdfs:comment")
                  (property-m "rdfs:comment")
-                 (assoc :description (get-comment-string (property-m "rdfs:comment") renamed-classes))
+                 (assoc :description (get-comment-string (property-m "rdfs:comment") renamed-pages))
                  (= schema-type :page)
                  (= schema-type :page)
                  (assoc :classes (let [invalid-classes (remove class-uuids range-includes)
                  (assoc :classes (let [invalid-classes (remove class-uuids range-includes)
                                        _ (when (seq invalid-classes)
                                        _ (when (seq invalid-classes)
@@ -131,7 +134,7 @@
     {(keyword (strip-schema-prefix (property-m "@id")))
     {(keyword (strip-schema-prefix (property-m "@id")))
      {:block/uuid prop-uuid
      {:block/uuid prop-uuid
       :block/schema schema
       :block/schema schema
-      :properties {:url (string/replace-first (property-m "@id") "schema:" "https://schema.org/")}}}))
+      :properties {:url url}}}))
 
 
 (defn- get-class-to-properties
 (defn- get-class-to-properties
   "Given a vec of class ids and a vec of properties map to process, return a map of
   "Given a vec of class ids and a vec of properties map to process, return a map of
@@ -162,21 +165,60 @@
     (and (seq range-includes)
     (and (seq range-includes)
          (every? (fn [x] (contains? unsupported-data-types x)) range-includes))))
          (every? (fn [x] (contains? unsupported-data-types x)) range-includes))))
 
 
+(defn- get-vector-conflicts
+  "Given a seq of tuples returns a seq of tuples that conflict i.e. their first element
+   has a case insensitive conflict/duplicate with another. An example conflict:
+   [[\"schema:businessFunction\" :property] [\"schema:BusinessFunction\" :class]]"
+  [tuples-seq]
+  (->> tuples-seq
+       (group-by (comp common-util/page-name-sanity-lc first))
+       (filter #(> (count (val %)) 1))
+       vals))
+
+(defn- detect-final-conflicts
+  "Does one final detection for conflicts after everything has been renamed"
+  [all-properties all-classes page-tuples]
+  (let [property-ids (map #(vector (% "@id") :property) all-properties)
+        class-ids (map #(vector (% "@id") :class) all-classes)
+        existing-conflicts (get-vector-conflicts (concat property-ids class-ids page-tuples))]
+    (when (seq existing-conflicts) (prn :CONFLICTS existing-conflicts))
+    (assert (empty? existing-conflicts)
+            "There are no conflicts between existing pages, schema classes and properties")))
+
+(defn- detect-property-conflicts-and-get-renamed-properties
+  "Detects conflicts between properties and existing pages and returns renamed properties"
+  [property-ids existing-pages {:keys [verbose]}]
+  (let [conflicts (get-vector-conflicts (concat property-ids existing-pages))
+        _ (assert (every? #(= 2 (count %)) conflicts) "All conflicts must only be between two elements")
+        renamed-properties (->> conflicts
+                                (map #(-> % second first))
+                                ;; Renaming properties '_property' suffix guarantees uniqueness
+                                ;; b/c schema.org doesn't use '_' in their names
+                                (map #(vector % (str % "_property")))
+                                (into {}))]
+    (if verbose
+      (println "Renaming the following properties because they have names that conflict with Logseq's built in pages"
+               (keys renamed-properties) "\n")
+      (println "Renaming" (count renamed-properties) "properties due to page name conflicts"))
+    renamed-properties))
+
 (defn- detect-id-conflicts-and-get-renamed-classes
 (defn- detect-id-conflicts-and-get-renamed-classes
-  "Properties and class names conflict in Logseq because schema.org names are
-  case sensitive whereas Logseq's :block/name is case insensitive. This is dealt
-  with by appending a '_Class' suffix to conflicting classes.  If this strategy
-  changes, be sure to update schema->logseq-data-types"
-  [property-ids class-ids {:keys [verbose]}]
-  (let [conflicts
-        (->> (concat property-ids class-ids)
-             (group-by (comp common-util/page-name-sanity-lc first))
-             (filter #(> (count (val %)) 1))
-             vals)
+  "Detects conflicts between classes AND properties and existing
+  pages. Renames any detected conflicts. Properties and class names conflict in
+  Logseq because schema.org names are case sensitive whereas Logseq's
+  :block/name is case insensitive. This is dealt with by appending a '_Class'
+  suffix to conflicting classes.  If this strategy changes, be sure to update
+  schema->logseq-data-types"
+  [property-ids class-ids existing-pages {:keys [verbose]}]
+  (let [conflicts (get-vector-conflicts (concat property-ids class-ids))
         ;; If this assertion fails then renamed-classes approach to resolving
         ;; If this assertion fails then renamed-classes approach to resolving
         ;; conflicts may need to be revisited
         ;; conflicts may need to be revisited
-        _ (assert (every? #(= (map second %) [:property :class]) conflicts)
-                  "All conflicts are between a property and class")
+        _ (assert (every? #(= 2 (count %)) conflicts) "All conflicts must only be between two elements")
+        existing-conflicts (get-vector-conflicts (concat class-ids existing-pages))
+        _ (when (seq existing-conflicts) (prn :EXISTING-CLASS-CONFLICTS existing-conflicts))
+        ;; Add existing-conflicts to conflicts if this ever fails
+        _ (assert (empty? existing-conflicts)
+                  "There are no conflicts between existing pages and schema classes and properties")
         renamed-classes (->> conflicts
         renamed-classes (->> conflicts
                              (map #(-> % second first))
                              (map #(-> % second first))
                              ;; Renaming classes with '_Class' suffix guarantees uniqueness
                              ;; Renaming classes with '_Class' suffix guarantees uniqueness
@@ -187,7 +229,6 @@
       (println "Renaming the following classes because they have property names that conflict with Logseq's case insensitive :block/name:"
       (println "Renaming the following classes because they have property names that conflict with Logseq's case insensitive :block/name:"
                (keys renamed-classes) "\n")
                (keys renamed-classes) "\n")
       (println "Renaming" (count renamed-classes) "classes due to page name conflicts"))
       (println "Renaming" (count renamed-classes) "classes due to page name conflicts"))
-        ;; Looks for all instances of a renamed class and updates them to the renamed class reference
     renamed-classes))
     renamed-classes))
 
 
 (defn- get-all-properties [schema-data {:keys [verbose]}]
 (defn- get-all-properties [schema-data {:keys [verbose]}]
@@ -232,39 +273,47 @@
 
 
 (defn- get-all-classes-and-properties
 (defn- get-all-classes-and-properties
   "Get all classes and properties from raw json file"
   "Get all classes and properties from raw json file"
-  [schema-data options]
+  [schema-data existing-pages options]
   (let [;; TODO: See if it's worth pulling in non-types like schema:MusicReleaseFormatType
   (let [;; TODO: See if it's worth pulling in non-types like schema:MusicReleaseFormatType
         all-classes* (filter #(contains? (set (as-> (% "@type") type'
         all-classes* (filter #(contains? (set (as-> (% "@type") type'
                                                 (if (string? type') [type'] type')))
                                                 (if (string? type') [type'] type')))
                                          "rdfs:Class")
                                          "rdfs:Class")
                              schema-data)
                              schema-data)
         all-properties* (get-all-properties schema-data options)
         all-properties* (get-all-properties schema-data options)
+        property-tuples (map #(vector (% "@id") :property) all-properties*)
+        class-tuples (map #(vector (% "@id") :class) all-classes*)
+        page-tuples (map #(vector (str "schema:" %) :page) existing-pages)
         renamed-classes (detect-id-conflicts-and-get-renamed-classes
         renamed-classes (detect-id-conflicts-and-get-renamed-classes
-                         (map #(vector (% "@id") :property) all-properties*)
-                         (map #(vector (% "@id") :class) all-classes*)
-                         options)
-        rename-class-ids (fn [m]
-                           (w/postwalk (fn [x]
-                                         (if-let [new-class (and (map? x) (renamed-classes (x "@id")))]
-                                           (merge x {"@id" new-class})
-                                           x)) m))
+                         property-tuples class-tuples page-tuples options)
+        renamed-properties (detect-property-conflicts-and-get-renamed-properties
+                            property-tuples page-tuples options)
+        renamed-pages (merge renamed-classes renamed-properties)
         ;; Updates keys like @id, @subClassOf
         ;; Updates keys like @id, @subClassOf
-        all-classes (map rename-class-ids all-classes*)
+        rename-page-ids (fn [m]
+                          (w/postwalk (fn [x]
+                                        (if-let [new-page (and (map? x) (renamed-pages (x "@id")))]
+                                          (merge x {"@id" new-page})
+                                          x)) m))
         ;; Updates keys like @id, @rangeIncludes, @domainIncludes
         ;; Updates keys like @id, @rangeIncludes, @domainIncludes
-        all-properties (map rename-class-ids all-properties*)]
+        all-classes (map rename-page-ids all-classes*)
+        all-properties (map rename-page-ids all-properties*)]
+    (detect-final-conflicts all-properties all-classes page-tuples)
     {:all-classes all-classes
     {:all-classes all-classes
      :all-properties all-properties
      :all-properties all-properties
+     :renamed-properties (->> renamed-properties
+                              (map (fn [[k v]] [(strip-schema-prefix k) (strip-schema-prefix v)]))
+                              (into {}))
      :renamed-classes (->> renamed-classes
      :renamed-classes (->> renamed-classes
                            (map (fn [[k v]] [(strip-schema-prefix k) (strip-schema-prefix v)]))
                            (map (fn [[k v]] [(strip-schema-prefix k) (strip-schema-prefix v)]))
                            (into {}))}))
                            (into {}))}))
 
 
-(defn- create-init-data [options]
+(defn- create-init-data [existing-pages options]
   (let [schema-data (-> (str (fs/readFileSync "resources/schemaorg-current-https.json"))
   (let [schema-data (-> (str (fs/readFileSync "resources/schemaorg-current-https.json"))
                         js/JSON.parse
                         js/JSON.parse
                         (js->clj)
                         (js->clj)
                         (get "@graph"))
                         (get "@graph"))
-        {:keys [all-classes all-properties renamed-classes]}
-        (get-all-classes-and-properties schema-data options)
+        {:keys [all-classes all-properties renamed-classes renamed-properties]}
+        (get-all-classes-and-properties schema-data existing-pages options)
         ;; Generate data shared across pages and properties
         ;; Generate data shared across pages and properties
         class-map (->> all-classes
         class-map (->> all-classes
                        (map #(vector (% "@id") %))
                        (map #(vector (% "@id") %))
@@ -283,13 +332,17 @@
         property-uuids (->> select-properties
         property-uuids (->> select-properties
                             (map #(vector % (random-uuid)))
                             (map #(vector % (random-uuid)))
                             (into {}))
                             (into {}))
+        options' (assoc options
+                        :renamed-classes renamed-classes
+                        :renamed-properties renamed-properties
+                        :renamed-pages (merge renamed-properties renamed-classes))
         ;; Generate pages and properties
         ;; Generate pages and properties
         properties (generate-properties
         properties (generate-properties
                     (filter #(contains? select-properties (% "@id")) all-properties)
                     (filter #(contains? select-properties (% "@id")) all-properties)
-                    property-uuids class-map class-uuids (assoc options :renamed-classes renamed-classes))
+                    property-uuids class-map class-uuids options')
         pages (generate-pages
         pages (generate-pages
                (map #(class-map %) select-class-ids)
                (map #(class-map %) select-class-ids)
-               class-uuids class-to-properties property-uuids (assoc options :renamed-classes renamed-classes))]
+               class-uuids class-to-properties property-uuids options')]
     {:pages-and-blocks pages
     {:pages-and-blocks pages
      :properties properties}))
      :properties properties}))
 
 
@@ -297,9 +350,34 @@
   "Options spec"
   "Options spec"
   {:help {:alias :h
   {:help {:alias :h
           :desc "Print help"}
           :desc "Print help"}
+   :debug {:alias :d
+           :desc "Prints additional debug info and a schema.edn for debugging"}
    :verbose {:alias :v
    :verbose {:alias :v
              :desc "Verbose mode"}})
              :desc "Verbose mode"}})
 
 
+(defn- write-debug-file [blocks-tx db]
+  (let [block-uuid->name* (->> (d/q '[:find (pull ?b [:block/name :block/uuid]) :where [?b :block/name]] db)
+                               (map first)
+                               (map (juxt :block/uuid :block/name))
+                               (into {}))
+        block-uuid->name #(or (block-uuid->name* %) (throw (ex-info (str "No entity found for " %) {})))
+        ;; TODO: Figure out why some Thing's properties don't exist
+        block-uuid->name-please-fixme
+        #(or (block-uuid->name* %2) (println "WARNING: Page" (pr-str (:block/original-name %1)) "skipped uuid" %2))]
+    (fs/writeFileSync "schema-org.edn"
+                      (pr-str
+                       (->> blocks-tx
+                            (map (fn [m]
+                                   (cond-> (select-keys m [:block/name :block/type :block/original-name
+                                                           :block/properties :block/schema])
+                                     (seq (:block/properties m))
+                                     (update :block/properties #(update-keys % block-uuid->name))
+                                     (seq (get-in m [:block/schema :properties]))
+                                     (update-in [:block/schema :properties] #(mapv (partial block-uuid->name-please-fixme m) %))
+                                     (seq (get-in m [:block/schema :classes]))
+                                     (update-in [:block/schema :classes] #(mapv block-uuid->name %)))))
+                            set)))))
+
 (defn -main [args]
 (defn -main [args]
   (let [[graph-dir] args
   (let [[graph-dir] args
         options (cli/parse-opts args {:spec spec})
         options (cli/parse-opts args {:spec spec})
@@ -311,13 +389,15 @@
                         ((juxt node-path/dirname node-path/basename) graph-dir)
                         ((juxt node-path/dirname node-path/basename) graph-dir)
                         [(node-path/join (os/homedir) "logseq" "graphs") graph-dir])
                         [(node-path/join (os/homedir) "logseq" "graphs") graph-dir])
         conn (create-graph/init-conn dir db-name)
         conn (create-graph/init-conn dir db-name)
-        init-data (create-init-data options)
+        init-data (create-init-data (d/q '[:find [?name ...] :where [?b :block/name ?name]] @conn)
+                                    options)
         blocks-tx (create-graph/create-blocks-tx init-data)]
         blocks-tx (create-graph/create-blocks-tx init-data)]
     (println "Generating" (str (count (filter :block/name blocks-tx)) " pages with "
     (println "Generating" (str (count (filter :block/name blocks-tx)) " pages with "
                                (count (:pages-and-blocks init-data)) " classes and "
                                (count (:pages-and-blocks init-data)) " classes and "
                                (count (:properties init-data)) " properties ..."))
                                (count (:properties init-data)) " properties ..."))
     (d/transact! conn blocks-tx)
     (d/transact! conn blocks-tx)
     (when (:verbose options) (println "Transacted" (count (d/datoms @conn :eavt)) "datoms"))
     (when (:verbose options) (println "Transacted" (count (d/datoms @conn :eavt)) "datoms"))
+    (when (:debug options) (write-debug-file blocks-tx @conn))
     (println "Created graph" (str db-name "!"))))
     (println "Created graph" (str db-name "!"))))
 
 
 (when (= nbb/*file* (:file (meta #'-main)))
 (when (= nbb/*file* (:file (meta #'-main)))

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

@@ -2332,7 +2332,10 @@
       [:div.closed-values-properties.flex.flex-row.items-center.gap-1.select-none.h-full
       [:div.closed-values-properties.flex.flex-row.items-center.gap-1.select-none.h-full
        (for [pid closed-values-properties]
        (for [pid closed-values-properties]
          (when-let [property (db/entity [:block/uuid pid])]
          (when-let [property (db/entity [:block/uuid pid])]
-           (pv/property-value block property (get (:block/properties block) pid) {:icon? true :page-cp page-cp})))])))
+           (pv/property-value block property (get (:block/properties block) pid)
+                              {:icon? true
+                               :page-cp page-cp
+                               :inline-text inline-text})))])))
 
 
 (rum/defc ^:large-vars/cleanup-todo block-content < rum/reactive
 (rum/defc ^:large-vars/cleanup-todo block-content < rum/reactive
   [config {:block/keys [uuid content properties scheduled deadline format pre-block?] :as block} edit-input-id block-id slide? selected? *ref]
   [config {:block/keys [uuid content properties scheduled deadline format pre-block?] :as block} edit-input-id block-id slide? selected? *ref]

+ 75 - 28
src/main/frontend/components/imports.cljs

@@ -1,9 +1,11 @@
 (ns frontend.components.imports
 (ns frontend.components.imports
   "Import data into Logseq."
   "Import data into Logseq."
-  (:require [cljs.core.async.interop :refer [p->c]]
+  (:require [borkdude.rewrite-edn :as rewrite]
+            [cljs.core.async.interop :refer [p->c]]
             [clojure.core.async :as async]
             [clojure.core.async :as async]
             [clojure.edn :as edn]
             [clojure.edn :as edn]
             [clojure.string :as string]
             [clojure.string :as string]
+            [datascript.core :as d]
             [frontend.components.onboarding.setups :as setups]
             [frontend.components.onboarding.setups :as setups]
             [frontend.components.repo :as repo]
             [frontend.components.repo :as repo]
             [frontend.components.svg :as svg]
             [frontend.components.svg :as svg]
@@ -11,12 +13,15 @@
             [frontend.context.i18n :refer [t]]
             [frontend.context.i18n :refer [t]]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.fs :as fs]
             [frontend.fs :as fs]
-            [frontend.persist-db.browser :as db-browser]
+            [frontend.handler.common.config-edn :as config-edn-common-handler]
             [frontend.handler.db-based.editor :as db-editor-handler]
             [frontend.handler.db-based.editor :as db-editor-handler]
             [frontend.handler.import :as import-handler]
             [frontend.handler.import :as import-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
+            [frontend.handler.repo :as repo-handler]
             [frontend.handler.route :as route-handler]
             [frontend.handler.route :as route-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.ui :as ui-handler]
+            [frontend.modules.outliner.ui :as ui-outliner-tx]
+            [frontend.persist-db.browser :as db-browser]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.ui :as ui]
             [frontend.util :as util]
             [frontend.util :as util]
@@ -24,13 +29,13 @@
             [goog.functions :refer [debounce]]
             [goog.functions :refer [debounce]]
             [goog.object :as gobj]
             [goog.object :as gobj]
             [logseq.common.path :as path]
             [logseq.common.path :as path]
+            [logseq.common.util :as common-util]
+            [logseq.db :as ldb]
             [logseq.graph-parser :as graph-parser]
             [logseq.graph-parser :as graph-parser]
+            [logseq.outliner.core :as outliner-core]
             [medley.core :as medley]
             [medley.core :as medley]
             [promesa.core :as p]
             [promesa.core :as p]
-            [borkdude.rewrite-edn :as rewrite]
-            [rum.core :as rum]
-            [frontend.handler.repo :as repo-handler]
-            [frontend.handler.common.config-edn :as config-edn-common-handler]))
+            [rum.core :as rum]))
 
 
 ;; Can't name this component as `frontend.components.import` since shadow-cljs
 ;; Can't name this component as `frontend.components.import` since shadow-cljs
 ;; will complain about it.
 ;; will complain about it.
@@ -222,30 +227,71 @@
                    (db-editor-handler/save-file! "logseq/config.edn" migrated-content))
                    (db-editor-handler/save-file! "logseq/config.edn" migrated-content))
                   (edn/read-string migrated-content))))))
                   (edn/read-string migrated-content))))))
 
 
+(defn- build-hidden-favorites-page-blocks
+  [page-block-uuid-coll]
+  (map
+   (fn [uuid]
+     {:block/link [:block/uuid uuid]
+      :block/content ""
+      :block/format :markdown})
+   page-block-uuid-coll))
+
+(def hidden-favorites-page-name "$$$favorites")
+(def hidden-favorites-page-tx
+  {:block/uuid (d/squuid)
+   :block/name hidden-favorites-page-name
+   :block/original-name hidden-favorites-page-name
+   :block/journal? false
+   :block/type #{"hidden"}
+   :block/format :markdown})
+
+(defn- import-favorites-from-config-edn!
+  [db-conn repo config-file]
+  (let [now (inst-ms (js/Date.))]
+    (p/do!
+     (ldb/transact! repo [(assoc hidden-favorites-page-tx
+                                 :block/created-at now
+                                 :block/updated-at now)])
+     (p/let [content (when config-file (.text config-file))]
+       (when-let [content-edn (try (edn/read-string content)
+                                   (catch :default _ nil))]
+         (when-let [favorites (seq (:favorites content-edn))]
+           (when-let [page-block-uuid-coll
+                      (seq
+                       (keep (fn [page-name]
+                               (some-> (d/entity @db-conn [:block/name (common-util/page-name-sanity-lc page-name)])
+                                       :block/uuid))
+                             favorites))]
+             (let [page-entity (d/entity @db-conn [:block/name hidden-favorites-page-name])]
+               (ui-outliner-tx/transact!
+                {:outliner-op :insert-blocks}
+                (outliner-core/insert-blocks! repo db-conn (build-hidden-favorites-page-blocks page-block-uuid-coll)
+                                              page-entity {}))))))))))
 
 
-(rum/defc confirm-graph-name-dialog
-  [initial-name on-graph-name-confirmed]
-  (let [[input set-input!] (rum/use-state initial-name)
-        on-submit #(do (on-graph-name-confirmed input)
-                       (state/close-modal!))]
-    [:div.container
-     [:div.sm:flex.sm:items-start
-      [:div.mt-3.text-center.sm:mt-0.sm:text-left
-       [:h3#modal-headline.leading-6.font-medium
-        "Imported new graph name:"]]]
 
 
-     [:input.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2.mb-4
-      {:auto-focus true
-       :default-value input
-       :on-change (fn [e]
-                    (set-input! (util/evalue e)))
-       :on-key-press (fn [e]
-                       (when (= "Enter" (util/ekey e))
-                         (on-submit)))}]
-
-     [:div.mt-5.sm:mt-4.flex
-      (ui/button "Confirm"
-                 {:on-click on-submit})]]))
+(rum/defc confirm-graph-name-dialog
+          [initial-name on-graph-name-confirmed]
+          (let [[input set-input!] (rum/use-state initial-name)
+                on-submit #(do (on-graph-name-confirmed input)
+                               (state/close-modal!))]
+            [:div.container
+             [:div.sm:flex.sm:items-start
+              [:div.mt-3.text-center.sm:mt-0.sm:text-left
+               [:h3#modal-headline.leading-6.font-medium
+                "Imported new graph name:"]]]
+
+             [:input.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2.mb-4
+              {:auto-focus true
+               :default-value input
+               :on-change (fn [e]
+                            (set-input! (util/evalue e)))
+               :on-key-press (fn [e]
+                               (when (= "Enter" (util/ekey e))
+                                 (on-submit)))}]
+
+             [:div.mt-5.sm:mt-4.flex
+              (ui/button "Confirm"
+                         {:on-click on-submit})]]))
 
 
 (defn graph-folder-to-db-import-handler
 (defn graph-folder-to-db-import-handler
   "Import from a graph folder as a DB-based graph.
   "Import from a graph folder as a DB-based graph.
@@ -277,6 +323,7 @@
                                 (async/<! (p->c (import-config-file! config-file)))
                                 (async/<! (p->c (import-config-file! config-file)))
                                 (async/<! (import-from-asset-files! asset-files))
                                 (async/<! (import-from-asset-files! asset-files))
                                 (async/<! (import-from-doc-files! db-conn repo doc-files))
                                 (async/<! (import-from-doc-files! db-conn repo doc-files))
+                                (async/<! (p->c (import-favorites-from-config-edn! db-conn repo config-file)))
                                 (state/set-state! :graph/importing nil)
                                 (state/set-state! :graph/importing nil)
                                 (finished-cb)))))]
                                 (finished-cb)))))]
     (state/set-modal!
     (state/set-modal!

+ 39 - 32
src/main/frontend/components/property.cljs

@@ -373,6 +373,10 @@
 
 
 (rum/defcs property-input < rum/reactive
 (rum/defcs property-input < rum/reactive
   (rum/local false ::show-new-property-config?)
   (rum/local false ::show-new-property-config?)
+  {:will-unmount (fn [state]
+                   (when-let [*property-key (nth (:rum/args state) 1)]
+                     (reset! *property-key nil))
+                   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? _page-configure? in-block-container?]
                                                :as opts}]
                                                :as opts}]
@@ -435,38 +439,40 @@
                              nil))}]
                              nil))}]
          (property-select exclude-properties on-chosen input-opts)))]))
          (property-select exclude-properties on-chosen input-opts)))]))
 
 
-(rum/defcs new-property < rum/reactive rum/static
+(rum/defcs new-property < rum/reactive
   (rum/local false ::new-property?)
   (rum/local false ::new-property?)
   (rum/local nil ::property-key)
   (rum/local nil ::property-key)
   (rum/local nil ::property-value)
   (rum/local nil ::property-value)
-  [state block id opts]
+  [state block id keyboard-triggered? opts]
   (let [*new-property? (::new-property? state)
   (let [*new-property? (::new-property? state)
         container-id (state/sub :editor/properties-container)
         container-id (state/sub :editor/properties-container)
-        new-property? (and @*new-property? (= container-id id))]
-    [:div.ls-new-property
-     (let [*property-key (::property-key state)
-           *property-value (::property-value state)]
-       (cond
-         new-property?
-         (property-input block *property-key *property-value opts)
-
-         (and (or (db-property-handler/block-has-viewable-properties? block)
-                  (:page-configure? opts))
-              (not config/publishing?)
-              (not (:in-block-container? opts)))
-         [:a.fade-link.flex.add-property
-          {:on-click (fn []
-                       (state/set-state! :editor/block block)
-                       (state/set-state! :editor/properties-container id)
-                       (reset! *new-property? true)
-                       (reset! *property-key nil)
-                       (reset! *property-value nil))}
-          [:div.flex.flex-row.items-center {:style {:padding-left 1}}
-           (ui/icon "plus" {:size 15})
-           [:div.ml-1.text-sm {:style {:padding-left 2}} "Add property"]]]
-
-         :else
-         [:div {:style {:height 28}}]))]))
+        new-property? (or keyboard-triggered? (and @*new-property? (= container-id id)))]
+
+    (when-not (and (:in-block-container? opts) (not keyboard-triggered?))
+      [:div.ls-new-property
+       (let [*property-key (::property-key state)
+             *property-value (::property-value state)]
+         (cond
+           new-property?
+           (property-input block *property-key *property-value opts)
+
+           (and (or (db-property-handler/block-has-viewable-properties? block)
+                    (:page-configure? opts))
+                (not config/publishing?)
+                (not (:in-block-container? opts)))
+           [:a.fade-link.flex.add-property
+            {:on-click (fn []
+                         (reset! *property-key nil)
+                         (reset! *property-value nil)
+                         (state/set-state! :editor/block block)
+                         (state/set-state! :editor/properties-container id)
+                         (reset! *new-property? true))}
+            [:div.flex.flex-row.items-center {:style {:padding-left 1}}
+             (ui/icon "plus" {:size 15})
+             [:div.ml-1.text-sm {:style {:padding-left 2}} "Add property"]]]
+
+           :else
+           [:div {:style {:height 28}}]))])))
 
 
 (defn- property-collapsed?
 (defn- property-collapsed?
   [block property]
   [block property]
@@ -626,7 +632,7 @@
 (rum/defcs ^:large-vars/cleanup-todo properties-area < rum/reactive
 (rum/defcs ^:large-vars/cleanup-todo properties-area < rum/reactive
   {:init (fn [state]
   {:init (fn [state]
            (assoc state ::id (str (random-uuid))))}
            (assoc state ::id (str (random-uuid))))}
-  [state target-block _edit-input-id {:keys [in-block-container? page-configure? class-schema?] :as opts}]
+  [state target-block edit-input-id {:keys [in-block-container? page-configure? class-schema?] :as opts}]
   (let [id (::id state)
   (let [id (::id state)
         block (resolve-linked-block-if-exists target-block)
         block (resolve-linked-block-if-exists target-block)
         block-properties (:block/properties block)
         block-properties (:block/properties block)
@@ -688,10 +694,12 @@
                                 (recur (rest classes)
                                 (recur (rest classes)
                                        (set/union properties (set cur-properties))
                                        (set/union properties (set cur-properties))
                                        (conj result [class cur-properties])))
                                        (conj result [class cur-properties])))
-                              result))]
+                              result))
+        keyboard-triggered? (= (state/sub :editor/new-property-input-id) edit-input-id)]
     (when-not (and (empty? block-own-properties)
     (when-not (and (empty? block-own-properties)
                    (empty? class->properties)
                    (empty? class->properties)
-                   (not (:page-configure? opts)))
+                   (not (:page-configure? opts))
+                   (not keyboard-triggered?))
       [:div.ls-properties-area (cond-> (if in-block-container?
       [:div.ls-properties-area (cond-> (if in-block-container?
                                          {:id id}
                                          {:id id}
                                          {:id id
                                          {:id id
@@ -703,8 +711,7 @@
        (when (and (seq full-hidden-properties) (not class-schema?) (not config/publishing?))
        (when (and (seq full-hidden-properties) (not class-schema?) (not config/publishing?))
          (hidden-properties block full-hidden-properties opts))
          (hidden-properties block full-hidden-properties opts))
 
 
-       (when (not in-block-container?)
-         (rum/with-key (new-property block id opts) (str id "-add-property")))
+       (rum/with-key (new-property block id keyboard-triggered? opts) (str id "-add-property"))
 
 
        (when (and (seq class->properties) (not one-class?))
        (when (and (seq class->properties) (not one-class?))
          (let [page-cp (:page-cp opts)]
          (let [page-cp (:page-cp opts)]

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

@@ -34,6 +34,7 @@
   ([property-configure-check?]
   ([property-configure-check?]
    (when (or (and property-configure-check? (not (:editor/property-configure? @state/state)))
    (when (or (and property-configure-check? (not (:editor/property-configure? @state/state)))
              (not property-configure-check?))
              (not property-configure-check?))
+     (state/set-state! :editor/new-property-input-id nil)
      (state/clear-edit!))))
      (state/clear-edit!))))
 
 
 (defn set-editing!
 (defn set-editing!
@@ -208,7 +209,8 @@
 
 
                  :else
                  :else
                  (model/get-all-page-original-names repo))
                  (model/get-all-page-original-names repo))
-               distinct)
+               distinct
+               (remove (fn [p] (util/uuid-string? (str p)))))
         options (map (fn [p] {:value p}) pages)
         options (map (fn [p] {:value p}) pages)
         string-classes (remove #(= :logseq.class %) classes)
         string-classes (remove #(= :logseq.class %) classes)
         opts' (cond->
         opts' (cond->
@@ -343,7 +345,8 @@
            esc? (= (util/ekey e) "Escape")
            esc? (= (util/ekey e) "Escape")
            backspace? (= (util/ekey e) "Backspace")
            backspace? (= (util/ekey e) "Backspace")
            new-value (util/evalue e)
            new-value (util/evalue e)
-           new-property? (:editor/properties-container @state/state)]
+           new-property? (or @(:editor/properties-container @state/state)
+                             @(:editor/new-property-input-id @state/state))]
        (when (and (or enter? esc? backspace?)
        (when (and (or enter? esc? backspace?)
                   (not (state/get-editor-action)))
                   (not (state/get-editor-action)))
          (when-not backspace? (util/stop e))
          (when-not backspace? (util/stop e))

+ 32 - 13
src/main/frontend/db_worker.cljs

@@ -31,6 +31,7 @@
 (defonce *datascript-conns worker-state/*datascript-conns)
 (defonce *datascript-conns worker-state/*datascript-conns)
 (defonce *opfs-pools worker-state/*opfs-pools)
 (defonce *opfs-pools worker-state/*opfs-pools)
 (defonce *publishing? (atom false))
 (defonce *publishing? (atom false))
+(defonce *store-jobs (atom #{}))
 
 
 (defn- get-pool-name
 (defn- get-pool-name
   [graph-name]
   [graph-name]
@@ -104,13 +105,15 @@
   [repo _opts]
   [repo _opts]
   (reify IStorage
   (reify IStorage
     (-store [_ addr+data-seq delete-addrs]
     (-store [_ addr+data-seq delete-addrs]
-      (prn :debug (str "SQLite store addr+data count: " (count addr+data-seq)))
       (let [data (map
       (let [data (map
                   (fn [[addr data]]
                   (fn [[addr data]]
                     #js {:$addr addr
                     #js {:$addr addr
                          :$content (pr-str data)})
                          :$content (pr-str data)})
-                  addr+data-seq)]
-        (upsert-addr-content! repo data delete-addrs)))
+                  addr+data-seq)
+            p (p/do! (upsert-addr-content! repo data delete-addrs))]
+        (swap! *store-jobs conj p)
+        (p/then p (fn [] (swap! *store-jobs disj p)))
+        p))
 
 
     (-restore [_ addr]
     (-restore [_ addr]
       (restore-data-from-addr repo addr))))
       (restore-data-from-addr repo addr))))
@@ -260,9 +263,16 @@
   (createOrOpenDB
   (createOrOpenDB
    [_this repo & {:keys [close-other-db?]
    [_this repo & {:keys [close-other-db?]
                   :or {close-other-db? true}}]
                   :or {close-other-db? true}}]
-   (p/let [_ (when close-other-db?
-               (close-other-dbs! repo))]
-     (create-or-open-db! repo)))
+   (p/do!
+    ;; Store the current db if store jobs not finished yet
+    (when (seq @*store-jobs)
+      (-> (p/all @*store-jobs)
+          (p/then (fn [_]
+                    (reset! *store-jobs #{})
+                    (println "DB store job finished")))))
+    (when close-other-db?
+      (close-other-dbs! repo))
+    (create-or-open-db! repo)))
 
 
   (getMaxTx
   (getMaxTx
    [_this repo]
    [_this repo]
@@ -318,7 +328,7 @@
          nil)
          nil)
        (catch :default e
        (catch :default e
          (prn :debug :error)
          (prn :debug :error)
-         (js/console.error e)))))
+         (js/console.error e tx-data)))))
 
 
   (getInitialData
   (getInitialData
    [_this repo]
    [_this repo]
@@ -404,12 +414,21 @@
        (bean/->js {:result result}))))
        (bean/->js {:result result}))))
 
 
   (file-writes-finished?
   (file-writes-finished?
-   [this]
-   (if (empty? @file/*writes)
-     true
-     (do
-       (js/console.log "Unfinished file writes:" @file/*writes)
-       false)))
+   [this repo]
+   (let [conn (worker-state/get-datascript-conn repo)
+         writes @file/*writes]
+
+     ;; Clean pages that have been deleted
+     (when conn
+       (swap! file/*writes (fn [writes]
+                             (->> writes
+                                  (remove (fn [[_ pid]] (d/entity @conn pid)))
+                                  (into {})))))
+     (if (empty? writes)
+       true
+       (do
+         (prn "Unfinished file writes:" @file/*writes)
+         false))))
 
 
   (page-file-saved
   (page-file-saved
    [this request-id page-id]
    [this request-id page-id]

+ 21 - 17
src/main/frontend/handler/common/page.cljs

@@ -20,14 +20,13 @@
             [logseq.db :as ldb]
             [logseq.db :as ldb]
             [frontend.db.conn :as conn]
             [frontend.db.conn :as conn]
             [datascript.core :as d]
             [datascript.core :as d]
-            [frontend.handler.editor :as editor-handler]
             [frontend.modules.outliner.ui :as ui-outliner-tx]
             [frontend.modules.outliner.ui :as ui-outliner-tx]
             [logseq.outliner.core :as outliner-core]))
             [logseq.outliner.core :as outliner-core]))
 
 
 (defn build-hidden-page-tx-data
 (defn build-hidden-page-tx-data
   [page-name]
   [page-name]
   (let [page-name* (str "$$$" page-name)]
   (let [page-name* (str "$$$" page-name)]
-    (assoc (block/page-name->map page-name* false false)
+    (assoc (block/page-name->map page-name* true false)
            :block/type #{"hidden"}
            :block/type #{"hidden"}
            :block/format :markdown)))
            :block/format :markdown)))
 
 
@@ -51,8 +50,7 @@
    (let [repo (state/get-current-repo)
    (let [repo (state/get-current-repo)
          conn (db/get-db repo false)
          conn (db/get-db repo false)
          config (state/get-config repo)
          config (state/get-config repo)
-         _ (worker-page/create! repo conn config title options)
-         [_ page-name] (worker-page/get-title-and-pagename title)]
+         [_ page-name] (worker-page/create! repo conn config title options)]
      (when redirect?
      (when redirect?
        (route-handler/redirect-to-page! page-name))
        (route-handler/redirect-to-page! page-name))
      (when-let [first-block (first (:block/_left (db/entity [:block/name page-name])))]
      (when-let [first-block (first (:block/_left (db/entity [:block/name page-name])))]
@@ -68,8 +66,8 @@
    (p/let [repo (state/get-current-repo)
    (p/let [repo (state/get-current-repo)
            conn (db/get-db repo false)
            conn (db/get-db repo false)
            config (state/get-config repo)
            config (state/get-config repo)
-           _ (worker-page/create! repo conn config title options)
-           [_ page-name] (worker-page/get-title-and-pagename title)]
+           [p page-name] (worker-page/create! repo conn config title options)
+           _result p]
      (when redirect?
      (when redirect?
        (route-handler/redirect-to-page! page-name))
        (route-handler/redirect-to-page! page-name))
      (let [page (db/entity [:block/name page-name])]
      (let [page (db/entity [:block/name page-name])]
@@ -113,12 +111,12 @@
 (defn- find-block-in-favorites-page
 (defn- find-block-in-favorites-page
   [page-block-uuid]
   [page-block-uuid]
   (let [db (conn/get-db)
   (let [db (conn/get-db)
-        page-block-uuid-str (str page-block-uuid)
         blocks (ldb/get-page-blocks db favorites-page-name {})]
         blocks (ldb/get-page-blocks db favorites-page-name {})]
-    (some (fn [block]
-            (when (= page-block-uuid-str (:block/content block))
-              block))
-          blocks)))
+    (when-let [page-block-entity (d/entity db [:block/uuid page-block-uuid])]
+      (some (fn [block]
+              (when (= (:db/id (:block/link block)) (:db/id page-block-entity))
+                block))
+            blocks))))
 
 
 (defn favorited?-v2
 (defn favorited?-v2
   [page-block-uuid]
   [page-block-uuid]
@@ -128,13 +126,19 @@
 (defn <favorite-page!-v2
 (defn <favorite-page!-v2
   [page-block-uuid]
   [page-block-uuid]
   {:pre [(uuid? page-block-uuid)]}
   {:pre [(uuid? page-block-uuid)]}
-  (let [favorites-page (d/entity (conn/get-db) [:block/name favorites-page-name])
+  (let [repo (state/get-current-repo)
+        favorites-page (d/entity (conn/get-db) [:block/name favorites-page-name])
         favorites-page-tx-data (build-hidden-page-tx-data "favorites")]
         favorites-page-tx-data (build-hidden-page-tx-data "favorites")]
-    (p/do!
-     (when-not favorites-page (ldb/transact! nil [favorites-page-tx-data]))
-     (editor-handler/api-insert-new-block!
-      (str page-block-uuid)
-      {:page favorites-page-name :edit-block? false}))))
+    (when (d/entity (conn/get-db) [:block/uuid page-block-uuid])
+      (p/do!
+       (when-not favorites-page (ldb/transact! nil [favorites-page-tx-data]))
+       (ui-outliner-tx/transact!
+        {:outliner-op :insert-blocks}
+        (outliner-core/insert-blocks! repo (conn/get-db false) [{:block/link [:block/uuid page-block-uuid]
+                                                                 :block/content ""
+                                                                 :block/format :markdown}]
+                                      (d/entity (conn/get-db) [:block/name favorites-page-name])
+                                      {}))))))
 
 
 (defn <unfavorite-page!-v2
 (defn <unfavorite-page!-v2
   [page-block-uuid]
   [page-block-uuid]

+ 1 - 6
src/main/frontend/handler/db_based/property.cljs

@@ -105,12 +105,7 @@
                             :block/uuid property-uuid
                             :block/uuid property-uuid
                             :block/type "property"})]
                             :block/type "property"})]
                     {:outliner-op :save-block})
                     {:outliner-op :save-block})
-      (db/transact! repo [(sqlite-util/build-new-property
-                           (cond-> {:block/original-name k-name
-                                    :block/name (util/page-name-sanity-lc k-name)
-                                    :block/uuid property-uuid}
-                             (seq schema)
-                             (assoc :block/schema schema)))]
+      (db/transact! repo [(sqlite-util/build-new-property k-name schema property-uuid)]
                     {:outliner-op :insert-blocks}))))
                     {:outliner-op :insert-blocks}))))
 
 
 (defn validate-property-value
 (defn validate-property-value

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

@@ -345,9 +345,9 @@
                    :else
                    :else
                    (not has-children?))]
                    (not has-children?))]
     (p/do!
     (p/do!
-     (save-current-block! {:current-block current-block})
      (ui-outliner-tx/transact!
      (ui-outliner-tx/transact!
       {:outliner-op :insert-blocks}
       {:outliner-op :insert-blocks}
+       (save-current-block! {:current-block current-block})
        (outliner-core/insert-blocks! (state/get-current-repo) (db/get-db false)
        (outliner-core/insert-blocks! (state/get-current-repo) (db/get-db false)
                                     [new-block] current-block {:sibling? sibling?
                                     [new-block] current-block {:sibling? sibling?
                                                                :keep-uuid? keep-uuid?
                                                                :keep-uuid? keep-uuid?
@@ -408,7 +408,7 @@
                        (wrap-parse-block))
                        (wrap-parse-block))
         sibling? (when block-self? false)]
         sibling? (when block-self? false)]
     (p/let [_ (outliner-insert-block! config current-block next-block {:sibling? sibling?
     (p/let [_ (outliner-insert-block! config current-block next-block {:sibling? sibling?
-                                                              :keep-uuid? true})]
+                                                                       :keep-uuid? true})]
       (util/set-change-value input fst-block-text)
       (util/set-change-value input fst-block-text)
       (assoc next-block :block/content snd-block-text))))
       (assoc next-block :block/content snd-block-text))))
 
 

+ 12 - 10
src/main/frontend/handler/events.cljs

@@ -189,7 +189,7 @@
 
 
 (defmethod handle :graph/switch [[_ graph opts]]
 (defmethod handle :graph/switch [[_ graph opts]]
   (let [^js sqlite @db-browser/*worker]
   (let [^js sqlite @db-browser/*worker]
-    (p/let [writes-finished? (when sqlite (.file-writes-finished? sqlite))
+    (p/let [writes-finished? (when sqlite (.file-writes-finished? sqlite (state/get-current-repo)))
             request-finished? (ldb/request-finished?)]
             request-finished? (ldb/request-finished?)]
       (if (or (not request-finished?) (not writes-finished?)) ; TODO: test (:sync-graph/init? @state/state)
       (if (or (not request-finished?) (not writes-finished?)) ; TODO: test (:sync-graph/init? @state/state)
         (do
         (do
@@ -369,7 +369,7 @@
 (defmethod handle :file/not-matched-from-disk [[_ path disk-content db-content]]
 (defmethod handle :file/not-matched-from-disk [[_ path disk-content db-content]]
   (when-let [repo (state/get-current-repo)]
   (when-let [repo (state/get-current-repo)]
     (let [^js sqlite @db-browser/*worker]
     (let [^js sqlite @db-browser/*worker]
-      (p/let [writes-finished? (when sqlite (.file-writes-finished? sqlite))
+      (p/let [writes-finished? (when sqlite (.file-writes-finished? sqlite (state/get-current-repo)))
               request-finished? (ldb/request-finished?)]
               request-finished? (ldb/request-finished?)]
         (prn :debug :writes-finished? writes-finished?
         (prn :debug :writes-finished? writes-finished?
              :request-finished? request-finished?)
              :request-finished? request-finished?)
@@ -921,14 +921,16 @@
     (editor-handler/toggle-blocks-as-own-order-list! blocks)))
     (editor-handler/toggle-blocks-as-own-order-list! blocks)))
 
 
 (defmethod handle :editor/new-property [[_]]
 (defmethod handle :editor/new-property [[_]]
-  (when-let [edit-block (state/get-edit-block)]
-    (when-let [block-id (:block/uuid edit-block)]
-      (let [block (db/entity [:block/uuid block-id])
-            collapsed? (or (get-in @state/state [:ui/collapsed-blocks (state/get-current-repo) block-id])
-                           (:block/collapsed? block))]
-        (when collapsed?
-          (editor-handler/set-blocks-collapsed! [block-id] false)))))
-  (property-handler/editing-new-property!))
+  (p/do!
+    (when-let [edit-block (state/get-edit-block)]
+     (when-let [block-id (:block/uuid edit-block)]
+       (let [block (db/entity [:block/uuid block-id])
+             collapsed? (or (get-in @state/state [:ui/collapsed-blocks (state/get-current-repo) block-id])
+                            (:block/collapsed? block))]
+         (when collapsed?
+           (editor-handler/set-blocks-collapsed! [block-id] false)))))
+    (editor-handler/save-current-block!)
+    (property-handler/editing-new-property!)))
 
 
 (rum/defc multi-tabs-dialog
 (rum/defc multi-tabs-dialog
   []
   []

+ 14 - 11
src/main/frontend/handler/page.cljs

@@ -82,10 +82,12 @@
   (when-let [db (conn/get-db)]
   (when-let [db (conn/get-db)]
     (let [repo (state/get-current-repo)]
     (let [repo (state/get-current-repo)]
       (if (config/db-based-graph? repo)
       (if (config/db-based-graph? repo)
-        (let [blocks (ldb/get-page-blocks db page-common-handler/favorites-page-name {})]
+        (let [blocks (ldb/sort-by-left
+                      (ldb/get-page-blocks db page-common-handler/favorites-page-name {})
+                      (d/entity db [:block/name page-common-handler/favorites-page-name]))]
           (keep (fn [block]
           (keep (fn [block]
-                  (when-let [block-uuid (some-> (:block/content block) parse-uuid)]
-                    (d/entity db [:block/uuid block-uuid]))) blocks))
+                  (when-let [block-db-id (:db/id (:block/link block))]
+                    (d/entity db block-db-id))) blocks))
         (let [page-names (->> (:favorites (state/sub-config))
         (let [page-names (->> (:favorites (state/sub-config))
                               (remove string/blank?)
                               (remove string/blank?)
                               (filter string?)
                               (filter string?)
@@ -135,20 +137,21 @@
   [favorites]
   [favorites]
   (let [repo (state/get-current-repo)
   (let [repo (state/get-current-repo)
         conn (conn/get-db false)]
         conn (conn/get-db false)]
-    (when (d/entity @conn [:block/name page-common-handler/favorites-page-name])
-      (let [favorite-page-block-uuid-coll
+    (when-let [favorites-page-entity (d/entity @conn [:block/name page-common-handler/favorites-page-name])]
+      (let [favorite-page-block-db-id-coll
             (keep (fn [page-name]
             (keep (fn [page-name]
                     (some-> (d/entity @conn [:block/name (common-util/page-name-sanity-lc page-name)])
                     (some-> (d/entity @conn [:block/name (common-util/page-name-sanity-lc page-name)])
-                            :block/uuid
-                            str))
+                            :db/id))
                   favorites)
                   favorites)
-            current-blocks (ldb/get-page-blocks @conn page-common-handler/favorites-page-name {})]
+            current-blocks (ldb/sort-by-left (ldb/get-page-blocks @conn page-common-handler/favorites-page-name {})
+                                             favorites-page-entity)]
+        (prn :favorite-page-block-db-id-coll favorite-page-block-db-id-coll)
         (ui-outliner-tx/transact!
         (ui-outliner-tx/transact!
          {}
          {}
-         (doseq [[page-block-uuid block] (zipmap favorite-page-block-uuid-coll current-blocks)]
-           (when (not= page-block-uuid (:block/content block))
+         (doseq [[page-block-db-id block] (zipmap favorite-page-block-db-id-coll current-blocks)]
+           (when (not= page-block-db-id (:db/id (:block/link block)))
              (outliner-core/save-block! repo conn (state/get-date-formatter)
              (outliner-core/save-block! repo conn (state/get-date-formatter)
-                                        (assoc block :block/content page-block-uuid)))))))))
+                                        (assoc block :block/link page-block-db-id)))))))))
 
 
 (defn has-more-journals?
 (defn has-more-journals?
   []
   []

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

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

+ 17 - 1
src/main/frontend/mobile/mobile_bar.cljs

@@ -13,11 +13,21 @@
             [goog.dom :as gdom]
             [goog.dom :as gdom]
             [rum.core :as rum]))
             [rum.core :as rum]))
 
 
+
+(defn- blur-if-compositing
+  "Call blur on the textarea if it is in composition mode, let the IME commit the composing text"
+  []
+  (when-let [edit-input-id (and (state/editor-in-composition?)
+                                (state/get-edit-input-id))]
+    (let [textarea-el (gdom/getElement edit-input-id)]
+      (.blur textarea-el))))
+
 (rum/defc indent-outdent [indent? icon]
 (rum/defc indent-outdent [indent? icon]
   [:div
   [:div
    [:button.bottom-action
    [:button.bottom-action
     {:on-mouse-down (fn [e]
     {:on-mouse-down (fn [e]
                       (util/stop e)
                       (util/stop e)
+                      (blur-if-compositing)
                       (editor-handler/indent-outdent indent?))}
                       (editor-handler/indent-outdent indent?))}
     (ui/icon icon {:size ui/icon-size})]])
     (ui/icon icon {:size ui/icon-size})]])
 
 
@@ -91,7 +101,13 @@
         (command #(if (state/sub :document/mode?)
         (command #(if (state/sub :document/mode?)
                     (editor-handler/insert-new-block! nil)
                     (editor-handler/insert-new-block! nil)
                     (commands/simple-insert! parent-id "\n" {})) {:icon "arrow-back"})
                     (commands/simple-insert! parent-id "\n" {})) {:icon "arrow-back"})
-        (command editor-handler/cycle-todo! {:icon "checkbox"} true)
+        ;; On mobile devies, some IME(keyboard) uses composing mode.
+        ;; The composing text can be committed by losing focus.
+        ;; 100ms is enough to commit the composing text to db.
+        (command #(do
+                    (blur-if-compositing)
+                    (editor-handler/cycle-todo!))
+                 {:icon "checkbox"} true)
         (command #(mobile-camera/embed-photo parent-id) {:icon "camera"} true)
         (command #(mobile-camera/embed-photo parent-id) {:icon "camera"} true)
         (command history/undo! {:icon "rotate" :class "rotate-180"} true)
         (command history/undo! {:icon "rotate" :class "rotate-180"} true)
         (command history/redo! {:icon "rotate-clockwise" :class "rotate-180"} true)
         (command history/redo! {:icon "rotate-clockwise" :class "rotate-180"} true)

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

@@ -130,7 +130,8 @@
       :editor/in-composition?                false
       :editor/in-composition?                false
       :editor/content                        (atom {})
       :editor/content                        (atom {})
       :editor/block                          (atom nil)
       :editor/block                          (atom nil)
-      :editor/properties-container                           (atom nil)
+      :editor/new-property-input-id          (atom nil)
+      :editor/properties-container           (atom nil)
       :editor/block-dom-id                   (atom nil)
       :editor/block-dom-id                   (atom nil)
       :editor/set-timestamp-block            (atom nil) ;; click rendered block timestamp-cp to set timestamp
       :editor/set-timestamp-block            (atom nil) ;; click rendered block timestamp-cp to set timestamp
       :editor/last-input-time                (atom {})
       :editor/last-input-time                (atom {})

+ 10 - 6
src/main/frontend/worker/file.cljs

@@ -66,22 +66,26 @@
         blocks-count (ldb/get-page-blocks-count @conn page-db-id)
         blocks-count (ldb/get-page-blocks-count @conn page-db-id)
         blocks-just-deleted? (and (zero? blocks-count)
         blocks-just-deleted? (and (zero? blocks-count)
                                   (contains? #{:delete-blocks :move-blocks} outliner-op))]
                                   (contains? #{:delete-blocks :move-blocks} outliner-op))]
-    (when (or (>= blocks-count 1) blocks-just-deleted?)
+    (if (or (>= blocks-count 1) blocks-just-deleted?)
       (if (and (or (> blocks-count 500) whiteboard?)
       (if (and (or (> blocks-count 500) whiteboard?)
                (not (worker-state/tx-idle? repo {:diff 3000})))
                (not (worker-state/tx-idle? repo {:diff 3000})))
         (async/put! file-writes-chan [repo page-db-id outliner-op (tc/to-long (t/now)) request-id])
         (async/put! file-writes-chan [repo page-db-id outliner-op (tc/to-long (t/now)) request-id])
         (let [pull-keys (if whiteboard? whiteboard-blocks-pull-keys-with-persisted-ids '[*])
         (let [pull-keys (if whiteboard? whiteboard-blocks-pull-keys-with-persisted-ids '[*])
               blocks (ldb/get-page-blocks @conn (:block/name page-block) {:pull-keys pull-keys})
               blocks (ldb/get-page-blocks @conn (:block/name page-block) {:pull-keys pull-keys})
               blocks (if whiteboard? (map cleanup-whiteboard-block blocks) blocks)]
               blocks (if whiteboard? (map cleanup-whiteboard-block blocks) blocks)]
-          (when-not (and (= 1 (count blocks))
-                         (string/blank? (:block/content (first blocks)))
-                         (nil? (:block/file page-block))
-                         (not whiteboard?))
+          (if (and (= 1 (count blocks))
+                   (string/blank? (:block/content (first blocks)))
+                   (nil? (:block/file page-block))
+                   (not whiteboard?))
+            (dissoc-request! request-id)
             (let [tree-or-blocks (if whiteboard? blocks
             (let [tree-or-blocks (if whiteboard? blocks
                                      (otree/blocks->vec-tree repo @conn blocks (:block/name page-block)))]
                                      (otree/blocks->vec-tree repo @conn blocks (:block/name page-block)))]
               (if page-block
               (if page-block
                 (file/save-tree! repo conn page-block tree-or-blocks blocks-just-deleted? context request-id)
                 (file/save-tree! repo conn page-block tree-or-blocks blocks-just-deleted? context request-id)
-                (js/console.error (str "can't find page id: " page-db-id))))))))))
+                (do
+                  (js/console.error (str "can't find page id: " page-db-id))
+                  (dissoc-request! request-id)))))))
+      (dissoc-request! request-id))))
 
 
 (defn write-files!
 (defn write-files!
   [conn pages context]
   [conn pages context]

+ 6 - 1
src/main/frontend/worker/file/core.cljs

@@ -21,7 +21,12 @@
 
 
 (defn dissoc-request!
 (defn dissoc-request!
   [request-id]
   [request-id]
-  (swap! *writes dissoc request-id))
+  (when-let [page-id (get @*writes request-id)]
+    (let [old-page-request-ids (keep (fn [[r p]]
+                                       (when (and (= p page-id) (<= r request-id))
+                                         r)) @*writes)]
+      (when (seq old-page-request-ids)
+        (swap! *writes (fn [x] (apply dissoc x old-page-request-ids)))))))
 
 
 (defn- indented-block-content
 (defn- indented-block-content
   [content spaces-tabs]
   [content spaces-tabs]

+ 48 - 47
src/main/frontend/worker/handler/page.cljs

@@ -81,56 +81,57 @@
                                   (date/valid-journal-title? date-formatter title)))
                                   (date/valid-journal-title? date-formatter title)))
 
 
         [title page-name] (get-title-and-pagename title)
         [title page-name] (get-title-and-pagename title)
-        with-uuid? (if (uuid? uuid) uuid true)] ;; FIXME: prettier validation
-    (when (ldb/page-empty? @conn page-name)
-      (let [pages    (if split-namespace?
-                       (common-util/split-namespace-pages title)
-                       [title])
-            format   (or format (common-config/get-preferred-format config))
-            pages    (map (fn [page]
+        with-uuid? (if (uuid? uuid) uuid true)
+        result (when (ldb/page-empty? @conn page-name)
+                 (let [pages    (if split-namespace?
+                                  (common-util/split-namespace-pages title)
+                                  [title])
+                       format   (or format (common-config/get-preferred-format config))
+                       pages    (map (fn [page]
                              ;; only apply uuid to the deepest hierarchy of page to create if provided.
                              ;; only apply uuid to the deepest hierarchy of page to create if provided.
-                            (-> (gp-block/page-name->map page (if (= page title) with-uuid? true) @conn true date-formatter)
-                                (assoc :block/format format)))
-                          pages)
-            txs      (->> pages
+                                       (-> (gp-block/page-name->map page (if (= page title) with-uuid? true) @conn true date-formatter)
+                                           (assoc :block/format format)))
+                                     pages)
+                       txs      (->> pages
                            ;; for namespace pages, only last page need properties
                            ;; for namespace pages, only last page need properties
-                          drop-last
-                          (mapcat #(build-page-tx repo conn config date-formatter format nil % {}))
-                          (remove nil?))
-            txs      (map-indexed (fn [i page]
-                                    (if (zero? i)
-                                      page
-                                      (assoc page :block/namespace
-                                             [:block/uuid (:block/uuid (nth txs (dec i)))])))
-                                  txs)
-            page-txs (build-page-tx repo conn config date-formatter format properties (last pages) (select-keys options [:whiteboard? :class? :tags]))
-            page-txs (if (seq txs)
-                       (update page-txs 0
-                               (fn [p]
-                                 (assoc p :block/namespace [:block/uuid (:block/uuid (last txs))])))
-                       page-txs)
-            first-block-tx (when (and
-                                  create-first-block?
-                                  (not (or whiteboard? class?))
-                                  (ldb/page-empty? @conn (:db/id (d/entity @conn [:block/name page-name])))
+                                     drop-last
+                                     (mapcat #(build-page-tx repo conn config date-formatter format nil % {}))
+                                     (remove nil?))
+                       txs      (map-indexed (fn [i page]
+                                               (if (zero? i)
+                                                 page
+                                                 (assoc page :block/namespace
+                                                        [:block/uuid (:block/uuid (nth txs (dec i)))])))
+                                             txs)
+                       page-txs (build-page-tx repo conn config date-formatter format properties (last pages) (select-keys options [:whiteboard? :class? :tags]))
+                       page-txs (if (seq txs)
+                                  (update page-txs 0
+                                          (fn [p]
+                                            (assoc p :block/namespace [:block/uuid (:block/uuid (last txs))])))
                                   page-txs)
                                   page-txs)
-                             (let [page-id [:block/uuid (:block/uuid (first page-txs))]]
-                               [(sqlite-util/block-with-timestamps
-                                 {:block/uuid (ldb/new-block-id)
-                                  :block/page page-id
-                                  :block/parent page-id
-                                  :block/left page-id
-                                  :block/content ""
-                                  :block/format format})]))
-            txs      (concat
-                      txs
-                      page-txs
-                      first-block-tx)]
-        (when (seq txs)
-          (ldb/transact! conn txs (cond-> {:persist-op? persist-op?}
-                                    today-journal?
-                                    (assoc :create-today-journal? true
-                                           :today-journal-name page-name))))))))
+                       first-block-tx (when (and
+                                             create-first-block?
+                                             (not (or whiteboard? class?))
+                                             (ldb/page-empty? @conn (:db/id (d/entity @conn [:block/name page-name])))
+                                             page-txs)
+                                        (let [page-id [:block/uuid (:block/uuid (first page-txs))]]
+                                          [(sqlite-util/block-with-timestamps
+                                            {:block/uuid (ldb/new-block-id)
+                                             :block/page page-id
+                                             :block/parent page-id
+                                             :block/left page-id
+                                             :block/content ""
+                                             :block/format format})]))
+                       txs      (concat
+                                 txs
+                                 page-txs
+                                 first-block-tx)]
+                   (when (seq txs)
+                     (ldb/transact! conn txs (cond-> {:persist-op? persist-op?}
+                                               today-journal?
+                                               (assoc :create-today-journal? true
+                                                      :today-journal-name page-name))))))] ;; FIXME: prettier validation
+    [result page-name]))
 
 
 (defn db-refs->page
 (defn db-refs->page
   "Replace [[page name]] with page name"
   "Replace [[page name]] with page name"

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

@@ -82,7 +82,8 @@
               _ (when (sqlite-util/local-file-based-graph? repo)
               _ (when (sqlite-util/local-file-based-graph? repo)
                   (let [page-ids (distinct (map :db/id pages))]
                   (let [page-ids (distinct (map :db/id pages))]
                     (doseq [page-id page-ids]
                     (doseq [page-id page-ids]
-                      (file/sync-to-file repo page-id tx-meta))))
+                      (when (d/entity @conn page-id)
+                        (file/sync-to-file repo page-id tx-meta)))))
               deleted-block-uuids (set (outliner-pipeline/filter-deleted-blocks (:tx-data tx-report)))
               deleted-block-uuids (set (outliner-pipeline/filter-deleted-blocks (:tx-data tx-report)))
               replace-tx (concat
               replace-tx (concat
                           ;; block path refs
                           ;; block path refs

+ 4 - 4
yarn.lock

@@ -537,10 +537,10 @@
     "@jridgewell/resolve-uri" "^3.1.0"
     "@jridgewell/resolve-uri" "^3.1.0"
     "@jridgewell/sourcemap-codec" "^1.4.14"
     "@jridgewell/sourcemap-codec" "^1.4.14"
 
 
-"@logseq/[email protected].1":
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/@logseq/capacitor-file-sync/-/capacitor-file-sync-5.0.1.tgz#e154f715597785518ccd7d058f353acb67fbc2b8"
-  integrity sha512-C1fLSS53orxsUWBsNb6LKwuOdlEU9ZhxkweMjNKG9VaSkLFTFqpjFG36OTso23WQ7hC5e45jjXq79aoWuqJaKA==
+"@logseq/[email protected].2":
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/@logseq/capacitor-file-sync/-/capacitor-file-sync-5.0.2.tgz#10c56e35b41b1a0afd293c9b045fbcfe150c3477"
+  integrity sha512-FymsTeRtF66zG+oeO+ohZxWICMQMC8An4n9pdI0zz1WaGLer4oWC/lUghlC2DpztRLA32p0CH28tEzF5+2jARg==
 
 
 "@logseq/[email protected]":
 "@logseq/[email protected]":
   version "0.2.2"
   version "0.2.2"