Преглед изворни кода

fix: import Zotero pdf blocks (#12260)

fix: support zotero files when importing pdf annotations
Tienson Qin пре 1 недеља
родитељ
комит
33db791ac0

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

@@ -492,6 +492,11 @@
                                                    :hide? false
                                                    :hide? false
                                                    :public? true}
                                                    :public? true}
                                           :queryable? true}
                                           :queryable? true}
+     :logseq.property.asset/external-file-name {:title "External file name"
+                                                :schema {:type :string
+                                                         :hide? true
+                                                         :public? false}
+                                                :queryable? false}
      :logseq.property.asset/size {:title "File Size"
      :logseq.property.asset/size {:title "File Size"
                                   :schema {:type :raw-number
                                   :schema {:type :raw-number
                                            :hide? true
                                            :hide? true

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

@@ -37,7 +37,7 @@
          (map (juxt :major :minor)
          (map (juxt :major :minor)
               [(parse-schema-version x) (parse-schema-version y)])))
               [(parse-schema-version x) (parse-schema-version y)])))
 
 
-(def version (parse-schema-version "65.15"))
+(def version (parse-schema-version "65.16"))
 
 
 (defn major-version
 (defn major-version
   "Return a number.
   "Return a number.

+ 76 - 47
deps/graph-parser/src/logseq/graph_parser/exporter.cljs

@@ -889,10 +889,22 @@
          (apply str)
          (apply str)
          string/trim)))
          string/trim)))
 
 
+;; {:url ["Complex" {:protocol "zotero", :link "select/library/items/6VCW9QFJ"}], :label [["Plain" "Dechow and Struppa - 2015 - Intertwingled.pdf"]], :full_text "[Dechow and Struppa - 2015 - Intertwingled.pdf](zotero://select/library/items/6VCW9QFJ)", :metadata ""}
+(defn- get-zotero-local-pdf-path
+  [config m]
+  (let [link (:link (second (:url m)))
+        label (second (first (:label m)))
+        id (last (string/split link #"/"))]
+    (when (and link id label)
+      (when-let [zotero-data-dir (get-in config [:zotero/settings-v2 "default" :zotero-data-directory])]
+        {:link (str "zotero://" link)
+         :path (node-path/join zotero-data-dir "storage" id label)
+         :base label}))))
+
 (defn- walk-ast-blocks
 (defn- walk-ast-blocks
   "Walks each ast block in order to its full depth. Saves multiple ast types for
   "Walks each ast block in order to its full depth. Saves multiple ast types for
   use in build-block-tx. This walk is only done once for perf reasons"
   use in build-block-tx. This walk is only done once for perf reasons"
-  [ast-blocks]
+  [config ast-blocks]
   (let [results (atom {:simple-queries []
   (let [results (atom {:simple-queries []
                        :asset-links []
                        :asset-links []
                        :embeds []})]
                        :embeds []})]
@@ -901,10 +913,15 @@
        (cond
        (cond
          (and (vector? x)
          (and (vector? x)
               (= "Link" (first x))
               (= "Link" (first x))
-              (let [path (second (:url (second x)))]
-                (when (string? path)
-                  (or (common-config/local-relative-asset? path)
-                      (string/ends-with? path ".pdf")))))
+              (let [path-or-map (second (:url (second x)))]
+                (cond
+                  (string? path-or-map)
+                  (or (common-config/local-relative-asset? path-or-map)
+                      (string/ends-with? path-or-map ".pdf"))
+                  (and (map? path-or-map) (= "zotero" (:protocol path-or-map)) (string? (:link path-or-map)))
+                  (:link (get-zotero-local-pdf-path config (second x)))
+                  :else
+                  nil)))
          (swap! results update :asset-links conj x)
          (swap! results update :asset-links conj x)
          (and (vector? x)
          (and (vector? x)
               (= "Macro" (first x))
               (= "Macro" (first x))
@@ -1139,7 +1156,8 @@
           :logseq.property.asset/checksum (:checksum asset-data)
           :logseq.property.asset/checksum (:checksum asset-data)
           :logseq.property.asset/size (:size asset-data)}
           :logseq.property.asset/size (:size asset-data)}
          (when-let [external-url (:external-url asset-data)]
          (when-let [external-url (:external-url asset-data)]
-           {:logseq.property.asset/external-url external-url})))
+           {:logseq.property.asset/external-url external-url
+            :logseq.property.asset/external-file-name (:external-file-name asset-data)})))
 
 
 (defn- get-asset-block-id
 (defn- get-asset-block-id
   [assets path]
   [assets path]
@@ -1190,53 +1208,58 @@
 
 
 (defn- <handle-assets-in-block
 (defn- <handle-assets-in-block
   "If a block contains assets, creates them as #Asset nodes in the Asset page and references them in the block."
   "If a block contains assets, creates them as #Asset nodes in the Asset page and references them in the block."
-  [block {:keys [asset-links]} {:keys [assets ignored-assets pdf-annotation-pages]} {:keys [notify-user <get-file-stat] :as opts}]
+  [config block {:keys [asset-links]} {:keys [assets ignored-assets pdf-annotation-pages]} {:keys [notify-user <get-file-stat] :as opts}]
   (if (seq asset-links)
   (if (seq asset-links)
     (p/let [asset-maps* (p/all (map
     (p/let [asset-maps* (p/all (map
                                 (fn [asset-link]
                                 (fn [asset-link]
-                                  (p/let [path (-> asset-link second :url second)
+                                  (p/let [path* (-> asset-link second :url second)
+                                          {:keys [path link base]} (if (map? path*)
+                                                                     (get-zotero-local-pdf-path config (second asset-link))
+                                                                     {:path path*})
                                           asset-name (-> path asset-path->name)
                                           asset-name (-> path asset-path->name)
-                                          asset-data* (when asset-name (get @assets asset-name))
-                                          _ (when (and asset-name
+                                          asset-link-or-name (or link (-> path asset-path->name))
+                                          asset-data* (when asset-link-or-name (get @assets asset-link-or-name))
+                                          _ (when (and asset-link-or-name
                                                        (not asset-data*)
                                                        (not asset-data*)
                                                        (string/ends-with? path ".pdf")
                                                        (string/ends-with? path ".pdf")
                                                        (fn? <get-file-stat)) ; external pdf
                                                        (fn? <get-file-stat)) ; external pdf
                                               (->
                                               (->
                                                (p/let [^js stat (<get-file-stat path)]
                                                (p/let [^js stat (<get-file-stat path)]
-                                                 (swap! assets assoc asset-name
+                                                 (swap! assets assoc asset-link-or-name
                                                         {:asset-id (d/squuid)
                                                         {:asset-id (d/squuid)
                                                          :type "pdf"
                                                          :type "pdf"
                                                          ;; avoid using the real checksum since it could be the same with in-graph asset
                                                          ;; avoid using the real checksum since it could be the same with in-graph asset
                                                          :checksum "0000000000000000000000000000000000000000000000000000000000000000"
                                                          :checksum "0000000000000000000000000000000000000000000000000000000000000000"
                                                          :size (.-size stat)
                                                          :size (.-size stat)
-                                                         :external-url path}))
+                                                         :external-url (or link path)
+                                                         :external-file-name base}))
                                                (p/catch (fn [error]
                                                (p/catch (fn [error]
                                                           (js/console.error error)))))
                                                           (js/console.error error)))))
-                                          asset-data (when asset-name (get @assets asset-name))]
+                                          asset-data (when asset-link-or-name (get @assets asset-link-or-name))]
                                     (if asset-data
                                     (if asset-data
                                       (cond
                                       (cond
-                                        (not (get-asset-block-id assets asset-name))
-                                        (notify-user {:msg (str "Skipped creating asset " (pr-str asset-name) " because it has no asset id")
+                                        (not (get-asset-block-id assets asset-link-or-name))
+                                        (notify-user {:msg (str "Skipped creating asset " (pr-str asset-link-or-name) " because it has no asset id")
                                                       :level :error})
                                                       :level :error})
 
 
                                         ;; If asset tx is already built, no need to do it again
                                         ;; If asset tx is already built, no need to do it again
                                         (:asset-created? asset-data)
                                         (:asset-created? asset-data)
-                                        {:asset-name-uuid [asset-name (:asset-id asset-data)]}
+                                        {:asset-name-uuid [asset-link-or-name (:asset-id asset-data)]}
 
 
                                         :else
                                         :else
                                         (let [new-asset (merge (build-new-asset asset-data)
                                         (let [new-asset (merge (build-new-asset asset-data)
                                                                {:block/title (db-asset/asset-name->title (node-path/basename asset-name))
                                                                {:block/title (db-asset/asset-name->title (node-path/basename asset-name))
-                                                                :block/uuid (get-asset-block-id assets asset-name)}
+                                                                :block/uuid (get-asset-block-id assets asset-link-or-name)}
                                                                (when-let [metadata (not-empty (common-util/safe-read-map-string (:metadata (second asset-link))))]
                                                                (when-let [metadata (not-empty (common-util/safe-read-map-string (:metadata (second asset-link))))]
                                                                  {:logseq.property.asset/resize-metadata metadata}))
                                                                  {:logseq.property.asset/resize-metadata metadata}))
-                                              pdf-annotations-tx (when (= "pdf" (path/file-ext asset-name))
-                                                                   (build-pdf-annotations-tx asset-name assets new-asset pdf-annotation-pages opts))
+                                              pdf-annotations-tx (when (= "pdf" (path/file-ext asset-link-or-name))
+                                                                   (build-pdf-annotations-tx asset-link-or-name assets new-asset pdf-annotation-pages opts))
                                               asset-tx (concat [new-asset] pdf-annotations-tx)]
                                               asset-tx (concat [new-asset] pdf-annotations-tx)]
                                           ;; (prn :asset-added! (node-path/basename asset-name))
                                           ;; (prn :asset-added! (node-path/basename asset-name))
                                           ;; (cljs.pprint/pprint asset-link)
                                           ;; (cljs.pprint/pprint asset-link)
                                           ;; (prn :debug :asset-tx asset-tx)
                                           ;; (prn :debug :asset-tx asset-tx)
-                                          (swap! assets assoc-in [asset-name :asset-created?] true)
-                                          {:asset-name-uuid [asset-name (:block/uuid new-asset)]
+                                          (swap! assets assoc-in [asset-link-or-name :asset-created?] true)
+                                          {:asset-name-uuid [asset-link-or-name (:block/uuid new-asset)]
                                            :asset-tx asset-tx}))
                                            :asset-tx asset-tx}))
                                       (do
                                       (do
                                         (swap! ignored-assets conj
                                         (swap! ignored-assets conj
@@ -1290,18 +1313,18 @@
     block))
     block))
 
 
 (defn- <build-block-tx
 (defn- <build-block-tx
-  [db block* pre-blocks {:keys [page-names-to-uuids] :as per-file-state} {:keys [import-state journal-created-ats] :as options}]
+  [db config block* pre-blocks {:keys [page-names-to-uuids] :as per-file-state} {:keys [import-state journal-created-ats] :as options}]
   ;; (prn ::block-in block*)
   ;; (prn ::block-in block*)
-  (p/let [walked-ast-blocks (walk-ast-blocks (:block.temp/ast-blocks block*))
+  (p/let [walked-ast-blocks (walk-ast-blocks config (:block.temp/ast-blocks block*))
         ;; needs to come before update-block-refs to detect new property schemas
         ;; needs to come before update-block-refs to detect new property schemas
           {:keys [block properties-tx]}
           {:keys [block properties-tx]}
           (handle-block-properties block* db page-names-to-uuids (:block/refs block*) walked-ast-blocks options)
           (handle-block-properties block* db page-names-to-uuids (:block/refs block*) walked-ast-blocks options)
           {block-after-built-in-props :block deadline-properties-tx :properties-tx}
           {block-after-built-in-props :block deadline-properties-tx :properties-tx}
           (update-block-deadline-and-scheduled block page-names-to-uuids options)
           (update-block-deadline-and-scheduled block page-names-to-uuids options)
           {block-after-assets :block :keys [asset-blocks-tx]}
           {block-after-assets :block :keys [asset-blocks-tx]}
-          (<handle-assets-in-block block-after-built-in-props walked-ast-blocks import-state (select-keys options [:log-fn :notify-user :<get-file-stat]))
-
+          (<handle-assets-in-block config block-after-built-in-props walked-ast-blocks import-state (select-keys options [:log-fn :notify-user :<get-file-stat]))
           ;; :block/page should be [:block/page NAME]
           ;; :block/page should be [:block/page NAME]
+
           journal-page-created-at (some-> (:block/page block*) second journal-created-ats)
           journal-page-created-at (some-> (:block/page block*) second journal-created-ats)
           prepared-block (cond-> block-after-assets
           prepared-block (cond-> block-after-assets
                            journal-page-created-at
                            journal-page-created-at
@@ -1787,6 +1810,16 @@
   (when-let [nodes (seq (filter :block/name txs))]
   (when-let [nodes (seq (filter :block/name txs))]
     (swap! (:all-existing-page-uuids import-state) merge (into {} (map (juxt :block/uuid identity) nodes)))))
     (swap! (:all-existing-page-uuids import-state) merge (into {} (map (juxt :block/uuid identity) nodes)))))
 
 
+(defn- <build-blocks-tx
+  [conn config blocks pre-blocks per-file-state tx-options]
+  (p/loop [tx-data []
+           blocks (remove :block/pre-block? blocks)]
+    (if-let [block (first blocks)]
+      (p/let [block-tx-data (<build-block-tx @conn config block pre-blocks per-file-state
+                                             tx-options)]
+        (p/recur (concat tx-data block-tx-data) (rest blocks)))
+      tx-data)))
+
 (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:
 
 
@@ -1798,10 +1831,10 @@
 * :macros - map of macros for use with macro expansion
 * :macros - map of macros for use with macro expansion
 * :notify-user - Displays warnings to user without failing the import. Fn receives a map with :msg
 * :notify-user - Displays warnings to user without failing the import. Fn receives a map with :msg
 * :log-fn - Logs messages for development. Defaults to prn"
 * :log-fn - Logs messages for development. Defaults to prn"
-  [conn file content {:keys [notify-user log-fn]
-                      :or {notify-user #(println "[WARNING]" (:msg %))
-                           log-fn prn}
-                      :as *options}]
+  [conn config file content {:keys [notify-user log-fn]
+                             :or {notify-user #(println "[WARNING]" (:msg %))
+                                  log-fn prn}
+                             :as *options}]
   (p/let [options (assoc *options :notify-user notify-user :log-fn log-fn :file file)
   (p/let [options (assoc *options :notify-user notify-user :log-fn log-fn :file file)
           {:keys [pages blocks]} (extract-pages-and-blocks @conn file content options)
           {:keys [pages blocks]} (extract-pages-and-blocks @conn file content options)
           tx-options (merge (build-tx-options options)
           tx-options (merge (build-tx-options options)
@@ -1810,19 +1843,15 @@
           ;; Build page and block txs
           ;; Build page and block txs
           {:keys [pages-tx page-properties-tx per-file-state existing-pages]} (build-pages-tx conn pages blocks tx-options)
           {:keys [pages-tx page-properties-tx per-file-state existing-pages]} (build-pages-tx conn pages blocks tx-options)
           whiteboard-pages (->> pages-tx
           whiteboard-pages (->> pages-tx
-                              ;; support old and new whiteboards
+                                ;; support old and new whiteboards
                                 (filter ldb/whiteboard?)
                                 (filter ldb/whiteboard?)
                                 (map (fn [page-block]
                                 (map (fn [page-block]
                                        (-> page-block
                                        (-> page-block
                                            (assoc :logseq.property/ls-type :whiteboard-page)))))
                                            (assoc :logseq.property/ls-type :whiteboard-page)))))
           pre-blocks (->> blocks (keep #(when (:block/pre-block? %) (:block/uuid %))) set)
           pre-blocks (->> blocks (keep #(when (:block/pre-block? %) (:block/uuid %))) set)
-          blocks-tx (p/loop [tx-data []
-                             blocks (remove :block/pre-block? blocks)]
-                      (if-let [block (first blocks)]
-                        (p/let [block-tx-data (<build-block-tx @conn block pre-blocks per-file-state
-                                                               (assoc tx-options :whiteboard? (some? (seq whiteboard-pages))))]
-                          (p/recur (concat tx-data block-tx-data) (rest blocks)))
-                        tx-data))
+
+          blocks-tx (let [tx-options' (assoc tx-options :whiteboard? (some? (seq whiteboard-pages)))]
+                      (<build-blocks-tx conn config blocks pre-blocks per-file-state tx-options'))
           {:keys [property-pages-tx property-page-properties-tx] pages-tx' :pages-tx}
           {:keys [property-pages-tx property-page-properties-tx] pages-tx' :pages-tx}
           (split-pages-and-properties-tx pages-tx old-properties existing-pages (:import-state options) @(:upstream-properties tx-options))
           (split-pages-and-properties-tx pages-tx old-properties existing-pages (:import-state options) @(:upstream-properties tx-options))
           ;; _ (when (seq property-pages-tx) (cljs.pprint/pprint {:property-pages-tx property-pages-tx}))
           ;; _ (when (seq property-pages-tx) (cljs.pprint/pprint {:property-pages-tx property-pages-tx}))
@@ -1869,18 +1898,18 @@
 ;; =======================
 ;; =======================
 
 
 (defn- export-doc-file
 (defn- export-doc-file
-  [{:keys [path idx] :as file} conn <read-file
+  [{:keys [path idx] :as file} conn config <read-file
    {:keys [notify-user set-ui-state <export-file]
    {:keys [notify-user set-ui-state <export-file]
     :or {set-ui-state (constantly nil)
     :or {set-ui-state (constantly nil)
-         <export-file (fn <export-file [conn m opts]
-                        (<add-file-to-db-graph conn (:file/path m) (:file/content m) opts))}
+         <export-file (fn <export-file [conn config m opts]
+                        (<add-file-to-db-graph conn config (:file/path m) (:file/content m) opts))}
     :as options}]
     :as options}]
   ;; (prn :export-doc-file path idx)
   ;; (prn :export-doc-file path idx)
   (-> (p/let [_ (set-ui-state [:graph/importing-state :current-idx] (inc idx))
   (-> (p/let [_ (set-ui-state [:graph/importing-state :current-idx] (inc idx))
               _ (set-ui-state [:graph/importing-state :current-page] path)
               _ (set-ui-state [:graph/importing-state :current-page] path)
               content (<read-file file)
               content (<read-file file)
               m {:file/path path :file/content content}]
               m {:file/path path :file/content content}]
-        (<export-file conn m (dissoc options :set-ui-state :<export-file))
+        (<export-file conn config m (dissoc options :set-ui-state :<export-file))
         ;; returning val results in smoother ui updates
         ;; returning val results in smoother ui updates
         m)
         m)
       (p/catch (fn [error]
       (p/catch (fn [error]
@@ -1891,9 +1920,9 @@
 (defn export-doc-files
 (defn export-doc-files
   "Exports all user created files i.e. under journals/ and pages/.
   "Exports all user created files i.e. under journals/ and pages/.
    Recommended to use build-doc-options and pass that as options"
    Recommended to use build-doc-options and pass that as options"
-  [conn *doc-files <read-file {:keys [notify-user set-ui-state]
-                               :or {set-ui-state (constantly nil) notify-user prn}
-                               :as options}]
+  [conn config *doc-files <read-file {:keys [notify-user set-ui-state]
+                                      :or {set-ui-state (constantly nil) notify-user prn}
+                                      :as options}]
   (set-ui-state [:graph/importing-state :total] (count *doc-files))
   (set-ui-state [:graph/importing-state :total] (count *doc-files))
   (let [doc-files (mapv #(assoc %1 :idx %2)
   (let [doc-files (mapv #(assoc %1 :idx %2)
                         ;; Sort files to ensure reproducible import behavior
                         ;; Sort files to ensure reproducible import behavior
@@ -1902,10 +1931,10 @@
                                    [(not (string/starts-with? (node-path/basename path) "hls__")) path])
                                    [(not (string/starts-with? (node-path/basename path) "hls__")) path])
                                  *doc-files)
                                  *doc-files)
                         (range 0 (count *doc-files)))]
                         (range 0 (count *doc-files)))]
-    (-> (p/loop [_file-map (export-doc-file (get doc-files 0) conn <read-file options)
+    (-> (p/loop [_file-map (export-doc-file (get doc-files 0) conn config <read-file options)
                  i 0]
                  i 0]
           (when-not (>= i (dec (count doc-files)))
           (when-not (>= i (dec (count doc-files)))
-            (p/recur (export-doc-file (get doc-files (inc i)) conn <read-file options)
+            (p/recur (export-doc-file (get doc-files (inc i)) conn config <read-file options)
                      (inc i))))
                      (inc i))))
         (p/catch (fn [e]
         (p/catch (fn [e]
                    (notify-user {:msg (str "Import has unexpected error:\n" (.-message e))
                    (notify-user {:msg (str "Import has unexpected error:\n" (.-message e))
@@ -2145,7 +2174,7 @@
                                    <read-and-copy-asset
                                    <read-and-copy-asset
                                    (merge (select-keys options [:notify-user :set-ui-state :rpath-key])
                                    (merge (select-keys options [:notify-user :set-ui-state :rpath-key])
                                           {:assets (get-in doc-options [:import-state :assets])}))
                                           {:assets (get-in doc-options [:import-state :assets])}))
-        (export-doc-files conn doc-files <read-file doc-options)
+        (export-doc-files conn config doc-files <read-file doc-options)
         (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)
         (move-top-parent-pages-to-library conn repo-or-conn)
         (move-top-parent-pages-to-library conn repo-or-conn)

+ 1 - 1
deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs

@@ -141,7 +141,7 @@
                                                                                       (dissoc options :user-config :verbose))}
                                                                                       (dissoc options :user-config :verbose))}
                                                                 (select-keys options [:verbose])))
                                                                 (select-keys options [:verbose])))
               files' (mapv #(hash-map :path %) files)
               files' (mapv #(hash-map :path %) files)
-              _ (gp-exporter/export-doc-files conn files' <read-file doc-options)]
+              _ (gp-exporter/export-doc-files conn {} files' <read-file doc-options)]
         {:import-state (:import-state doc-options)})
         {:import-state (:import-state doc-options)})
       (p/finally (fn [_]
       (p/finally (fn [_]
                    (reset! gp-block/*export-to-db-graph? false)))))
                    (reset! gp-block/*export-to-db-graph? false)))))

+ 15 - 10
src/main/frontend/components/block.cljs

@@ -280,15 +280,16 @@
         asset-height (:logseq.property.asset/height asset-block)]
         asset-height (:logseq.property.asset/height asset-block)]
     (hooks/use-effect!
     (hooks/use-effect!
      (fn []
      (fn []
-       (when-not (or asset-width asset-height)
-         (measure-image!
-          src
-          (fn [width height]
-            (when (nil? (:logseq.property.asset/width asset-block))
-              (property-handler/set-block-properties! (state/get-current-repo)
-                                                      (:block/uuid asset-block)
-                                                      {:logseq.property.asset/width width
-                                                       :logseq.property.asset/height height})))))
+       (when (:block/uuid asset-block)
+         (when-not (or asset-width asset-height)
+           (measure-image!
+            src
+            (fn [width height]
+              (when (nil? (:logseq.property.asset/width asset-block))
+                (property-handler/set-block-properties! (state/get-current-repo)
+                                                        (:block/uuid asset-block)
+                                                        {:logseq.property.asset/width width
+                                                         :logseq.property.asset/height height}))))))
        (fn []))
        (fn []))
      [])
      [])
     (let [*el-ref (rum/use-ref nil)
     (let [*el-ref (rum/use-ref nil)
@@ -444,7 +445,11 @@
 
 
 (defn- open-pdf-file
 (defn- open-pdf-file
   [e block href]
   [e block href]
-  (let [href (or (:logseq.property.asset/external-url block) href)]
+  (let [href (if-let [url (:logseq.property.asset/external-url block)]
+               (if (string/starts-with? url "zotero://")
+                 (zotero/zotero-full-path (last (string/split url #"/")) (:logseq.property.asset/external-file-name block))
+                 url)
+               href)]
     (when-let [s (or href (some-> (.-target e) (.-dataset) (.-href)))]
     (when-let [s (or href (some-> (.-target e) (.-dataset) (.-href)))]
       (let [load$ (fn []
       (let [load$ (fn []
                     (p/let [href (or href
                     (p/let [href (or href

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

@@ -412,9 +412,9 @@
                    :<read-and-copy-asset #(read-and-copy-asset repo (config/get-repo-dir repo) %1 %2 %3)
                    :<read-and-copy-asset #(read-and-copy-asset repo (config/get-repo-dir repo) %1 %2 %3)
                    ;; doc file options
                    ;; doc file options
                    ;; Write to frontend first as writing to worker first is poor ux with slow streaming changes
                    ;; Write to frontend first as writing to worker first is poor ux with slow streaming changes
-                   :<export-file (fn <export-file [conn m opts]
+                   :<export-file (fn <export-file [conn config m opts]
                                    (p/let [tx-reports
                                    (p/let [tx-reports
-                                           (gp-exporter/<add-file-to-db-graph conn (:file/path m) (:file/content m) opts)]
+                                           (gp-exporter/<add-file-to-db-graph conn config (:file/path m) (:file/content m) opts)]
                                      (doseq [tx-report tx-reports]
                                      (doseq [tx-report tx-reports]
                                        (db-browser/transact! repo (:tx-data tx-report) (:tx-meta tx-report)))))}
                                        (db-browser/transact! repo (:tx-data tx-report) (:tx-meta tx-report)))))}
           {:keys [files import-state]} (gp-exporter/export-file-graph repo db-conn config-file *files options)]
           {:keys [files import-state]} (gp-exporter/export-file-graph repo db-conn config-file *files options)]

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

@@ -44,8 +44,9 @@
 ;; TODO: support :string editing
 ;; TODO: support :string editing
 (defonce string-value-on-click
 (defonce string-value-on-click
   {:logseq.property.asset/external-url
   {:logseq.property.asset/external-url
-   (fn [block]
-     (state/pub-event! [:asset/dialog-edit-external-url block]))})
+   (fn [block property]
+     (when-not (string/starts-with? (get block (:db/ident property)) "zotero://")
+       (state/pub-event! [:asset/dialog-edit-external-url block])))})
 
 
 (defn- entity-map?
 (defn- entity-map?
   [m]
   [m]
@@ -1251,7 +1252,7 @@
                         (:db/ident property))
                         (:db/ident property))
            [:div.w-full {:on-click (fn []
            [:div.w-full {:on-click (fn []
                                      (let [f (get string-value-on-click (:db/ident property))]
                                      (let [f (get string-value-on-click (:db/ident property))]
-                                       (f block)))}
+                                       (f block property)))}
             content]
             content]
            content)))]))
            content)))]))
 
 

+ 10 - 7
src/main/frontend/extensions/zotero.cljs

@@ -480,18 +480,21 @@
      :target "_blank"
      :target "_blank"
      :href full-path)))
      :href full-path)))
 
 
+(defn zotero-full-path
+  [item-key filename]
+  (str "file://"
+       (util/node-path.join
+        (setting/setting :zotero-data-directory)
+        "storage"
+        item-key
+        filename)))
+
 (rum/defc zotero-imported-file
 (rum/defc zotero-imported-file
   [item-key filename]
   [item-key filename]
   (if (string/blank? (setting/setting :zotero-data-directory))
   (if (string/blank? (setting/setting :zotero-data-directory))
     [:p.warning "This is a zotero imported file, setting Zotero data directory would allow you to open the file in Logseq"]
     [:p.warning "This is a zotero imported file, setting Zotero data directory would allow you to open the file in Logseq"]
     (let [filename (read-string filename)
     (let [filename (read-string filename)
-          full-path
-          (str "file://"
-               (util/node-path.join
-                (setting/setting :zotero-data-directory)
-                "storage"
-                item-key
-                filename))]
+          full-path (zotero-full-path item-key filename)]
       (open-button full-path))))
       (open-button full-path))))
 
 
 (rum/defc zotero-linked-file
 (rum/defc zotero-linked-file

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

@@ -191,7 +191,8 @@
    ["65.14" {:properties [:logseq.property.asset/external-src]}]
    ["65.14" {:properties [:logseq.property.asset/external-src]}]
    ["65.15" (rename-properties {:logseq.property.asset/external-src
    ["65.15" (rename-properties {:logseq.property.asset/external-src
                                 :logseq.property.asset/external-url}
                                 :logseq.property.asset/external-url}
-                               {})]])
+                               {})]
+   ["65.16" {:properties [:logseq.property.asset/external-file-name]}]])
 
 
 (let [[major minor] (last (sort (map (comp (juxt :major :minor) db-schema/parse-schema-version first)
 (let [[major minor] (last (sort (map (comp (juxt :major :minor) db-schema/parse-schema-version first)
                                      schema-version->updates)))]
                                      schema-version->updates)))]

+ 7 - 7
src/test/frontend/worker/rtc/gen_client_op_test.cljs

@@ -167,10 +167,10 @@
                         :block/tags :block/title :db/cardinality}]
                         :block/tags :block/title :db/cardinality}]
     #_{:clj-kondo/ignore [:unresolved-symbol :invalid-arity]}
     #_{:clj-kondo/ignore [:unresolved-symbol :invalid-arity]}
     (is (->> (me/find (subject/generate-rtc-ops-from-property-entities [ent])
     (is (->> (me/find (subject/generate-rtc-ops-from-property-entities [ent])
-               ([:move _ {:block-uuid ?block-uuid}]
-                [:update-page _ {:block-uuid ?block-uuid}]
-                [:update _ {:block-uuid ?block-uuid :av-coll ([!av-coll-attrs . _ ...] ...)}])
-               !av-coll-attrs)
+                      ([:move _ {:block-uuid ?block-uuid}]
+                       [:update-page _ {:block-uuid ?block-uuid}]
+                       [:update _ {:block-uuid ?block-uuid :av-coll ([!av-coll-attrs . _ ...] ...)}])
+                      !av-coll-attrs)
              set
              set
              (set/difference av-coll-attrs)
              (set/difference av-coll-attrs)
              empty?))))
              empty?))))
@@ -183,9 +183,9 @@
                         :block/tags :block/title}]
                         :block/tags :block/title}]
     #_{:clj-kondo/ignore [:unresolved-symbol :invalid-arity]}
     #_{:clj-kondo/ignore [:unresolved-symbol :invalid-arity]}
     (is (->> (me/find (subject/generate-rtc-ops-from-class-entities [ent])
     (is (->> (me/find (subject/generate-rtc-ops-from-class-entities [ent])
-               ([:update-page _ {:block-uuid ?block-uuid}]
-                [:update _ {:block-uuid ?block-uuid :av-coll ([!av-coll-attrs . _ ...] ...)}])
-               !av-coll-attrs)
+                      ([:update-page _ {:block-uuid ?block-uuid}]
+                       [:update _ {:block-uuid ?block-uuid :av-coll ([!av-coll-attrs . _ ...] ...)}])
+                      !av-coll-attrs)
              set
              set
              (set/difference av-coll-attrs)
              (set/difference av-coll-attrs)
              empty?))))
              empty?))))