Browse Source

enhance(plugins): apis related improvements (#12266)

Charlie 22 giờ trước cách đây
mục cha
commit
fbe6b998b6

+ 69 - 0
clj-e2e/test/logseq/e2e/plugins_basic_test.clj

@@ -335,3 +335,72 @@
           result (ls-api-call! :editor.get_tag_objects "logseq.class/Task")]
       (is (= (count result) 1))
       (is (= "task 1" (get (first result) "title"))))))
+
+(deftest create-and-get-tag-test
+  (testing "create and get tag with title or ident"
+    (let [title "book1"
+          title-ident (str :plugin.class._test_plugin/book1)
+          tag1 (ls-api-call! :editor.createTag title)
+          tag2 (ls-api-call! :editor.getTag title)
+          tag3 (ls-api-call! :editor.getTag title-ident)
+          tag4 (ls-api-call! :editor.getTag (get tag1 "uuid"))]
+      (is (= (get tag1 "ident") title-ident) "create tag with title from test as plugin")
+      (is (= (get tag2 "ident") title-ident) "get tag with title")
+      (is (= (get tag3 "title") title) "get tag with ident")
+      (is (= (get tag4 "title") title) "get tag with uuid")))
+
+  (testing "add and remove tag extends"
+    (let [tag1 (ls-api-call! :editor.createTag "tag1")
+          tag2 (ls-api-call! :editor.createTag "tag2")
+          tag3 (ls-api-call! :editor.createTag "tag3")
+          id1 (get tag1 "id")
+          id2 (get tag2 "id")
+          id3 (get tag3 "id")
+          _ (ls-api-call! :editor.addTagExtends id1 id2)
+          tag1 (ls-api-call! :editor.getTag id1)]
+      (is (= (get tag1 ":logseq.property.class/extends") [id2]) "tag1 extends tag2 with db id")
+      (let [_ (ls-api-call! :editor.addTagExtends id1 id3)
+            tag1 (ls-api-call! :editor.getTag id1)]
+        (is (= (get tag1 ":logseq.property.class/extends") [id2 id3]) "tag1 extends tag2,tag3 with db ids"))
+      )))
+
+(deftest get-tags-by-name-test
+  (testing "get tags by exact name"
+    (let [tag-name "product"
+          tag1 (ls-api-call! :editor.createTag tag-name)
+          result (ls-api-call! :editor.getTagsByName tag-name)]
+      (is (= 1 (count result)) "should return exactly one tag")
+      (is (= (get tag1 "uuid") (get (first result) "uuid")) "should return the created tag")
+      (is (= (get tag1 "title") (get (first result) "title")) "tag title should match")))
+
+  (testing "get tags by name is case-insensitive"
+    (let [tag-name "TestTag123"
+          _ (ls-api-call! :editor.createTag tag-name)
+          result-lower (ls-api-call! :editor.getTagsByName "testtag123")
+          result-upper (ls-api-call! :editor.getTagsByName "TESTTAG123")
+          result-mixed (ls-api-call! :editor.getTagsByName "TeStTaG123")]
+      (is (= 1 (count result-lower)) "should find tag with lowercase search")
+      (is (= 1 (count result-upper)) "should find tag with uppercase search")
+      (is (= 1 (count result-mixed)) "should find tag with mixed case search")
+      (is (= (get (first result-lower) "uuid") (get (first result-upper) "uuid")) "all searches should return same tag")
+      (is (= (get (first result-lower) "uuid") (get (first result-mixed) "uuid")) "all searches should return same tag")))
+
+  (testing "get tags by name returns empty array for non-existent tag"
+    (let [result (ls-api-call! :editor.getTagsByName "NonExistentTag12345")]
+      (is (empty? result) "should return empty array for non-existent tag")))
+
+  (testing "get tags by name filters out non-tag pages"
+    (let [page-name "regular-page"
+          _ (page/new-page page-name)
+          result (ls-api-call! :editor.getTagsByName page-name)]
+      (is (empty? result) "should not return regular pages, only tags")))
+
+  (testing "get tags by name with multiple tags having similar names"
+    (let [tag1 (ls-api-call! :editor.createTag "category")
+          tag2 (ls-api-call! :editor.createTag "Category")
+          result (ls-api-call! :editor.getTagsByName "category")]
+      ;; Due to case-insensitive name normalization, both tags should be the same
+      (is (>= (count result) 1) "should return at least one tag")
+      ;; Verify the result contains valid tag structure
+      (is (string? (get (first result) "uuid")) "returned tag should have uuid")
+      (is (string? (get (first result) "title")) "returned tag should have title"))))

+ 30 - 20
deps/outliner/src/logseq/outliner/page.cljs

@@ -247,6 +247,7 @@
                (map (fn [id] (d/entity db [:block/uuid id])) tags)
                tags)
         class? (or class? (some (fn [t] (= :logseq.class/Tag (:db/ident t))) tags))
+        class-ident-namespace? (and class? class-ident-namespace (string? class-ident-namespace))
         title (sanitize-title title*)
         types (cond class?
                     #{:logseq.class/Tag}
@@ -258,29 +259,38 @@
                     (set (map :db/ident tags))
                     :else
                     #{:logseq.class/Page})
-        existing-page-id (first (ldb/page-exists? db title types))
+        existing-names-page (ldb/page-exists? db title types)
+        existing-page-id (some->> existing-names-page
+                                  (filter #(try (when-let [e (and class-ident-namespace? (d/entity db %))]
+                                                  (let [ns' (namespace (:db/ident e))]
+                                                    (= (str ns') class-ident-namespace)))
+                                                (catch :default _ false)))
+                                  (first))
         existing-page (some->> existing-page-id (d/entity db))]
     (if (and existing-page (not (:block/parent existing-page)))
       (let [tx-meta {:persist-op? persist-op?
                      :outliner-op :save-block}]
-        (when (and class?
-                   (not (ldb/class? existing-page))
-                   (ldb/internal-page? existing-page))
+        (if (and class?
+                 (not (ldb/class? existing-page))
+                 (ldb/internal-page? existing-page))
           ;; Convert existing page to class
           (let [tx-data [(merge (db-class/build-new-class db
                                                           (select-keys existing-page [:block/title :block/uuid :block/created-at])
-                                                          (when (and class? class-ident-namespace (string? class-ident-namespace))
+                                                          (when class-ident-namespace?
                                                             {:ident-namespace class-ident-namespace}))
                                 (select-keys existing-page [:db/ident]))
                          [:db/retract [:block/uuid (:block/uuid existing-page)] :block/tags :logseq.class/Page]]]
             {:tx-meta tx-meta
              :tx-data tx-data
              :page-uuid (:block/uuid existing-page)
-             :title (:block/title existing-page)})))
-      (let [page           (gp-block/page-name->map title db true date-formatter
-                                                    {:class? class?
-                                                     :page-uuid (when (uuid? uuid') uuid')
-                                                     :skip-existing-page-check? true})
+             :title (:block/title existing-page)})
+          ;; Just return existing page info
+          {:page-uuid (:block/uuid existing-page)
+           :title (:block/title existing-page)}))
+      (let [page (gp-block/page-name->map title db true date-formatter
+                                          {:class? class?
+                                           :page-uuid (when (uuid? uuid') uuid')
+                                           :skip-existing-page-check? true})
             [page parents'] (if (and (text/namespace-page? title) split-namespace?)
                               (let [pages (split-namespace-pages db page date-formatter class?)]
                                 [(last pages) (butlast pages)])
@@ -296,16 +306,16 @@
               (outliner-validate/validate-page-title-characters (str (:block/title parent)) {:node parent})))
 
           (let [page-uuid (:block/uuid page)
-                page-txs  (build-page-tx db properties page (select-keys options [:whiteboard? :class? :tags :class-ident-namespace]))
-                txs      (concat
-                          ;; transact doesn't support entities
-                          (remove de/entity? parents')
-                          page-txs)
+                page-txs (build-page-tx db properties page (select-keys options [:whiteboard? :class? :tags :class-ident-namespace]))
+                txs (concat
+                     ;; transact doesn't support entities
+                     (remove de/entity? parents')
+                     page-txs)
                 tx-meta (cond-> {:persist-op? persist-op?
                                  :outliner-op :create-page}
-                          today-journal?
-                          (assoc :create-today-journal? true
-                                 :today-journal-name title))]
+                                today-journal?
+                                (assoc :create-today-journal? true
+                                       :today-journal-name title))]
             {:tx-meta tx-meta
              :tx-data txs
              :title title
@@ -315,5 +325,5 @@
   [conn title opts]
   (let [{:keys [tx-meta tx-data title' page-uuid]} (create @conn title opts)]
     (when (seq tx-data)
-      (ldb/transact! conn tx-data tx-meta)
-      [title' page-uuid])))
+      (ldb/transact! conn tx-data tx-meta))
+    [title' page-uuid]))

+ 3 - 3
libs/package.json

@@ -14,8 +14,8 @@
     "build": "tsc && rm dist/*.js && npm run build:user",
     "lint": "prettier --check \"src/**/*.{ts, js}\"",
     "fix": "prettier --write \"src/**/*.{ts, js}\"",
-    "build:docs": "typedoc src/LSPlugin.user.ts",
-    "build:docs:json": "typedoc --plugin typedoc-plugin-lsp-docs src/LSPlugin.user.ts && typedoc --json docs/out.json ./src/LSPlugin.user.ts"
+    "build:docs": "typedoc --plugin typedoc-plugin-lsp-docs src/LSPlugin.user.ts",
+    "build:docs:json": "typedoc --json docs/out.json ./src/LSPlugin.user.ts"
   },
   "dependencies": {
     "csstype": "3.1.0",
@@ -41,7 +41,7 @@
     "terser-webpack-plugin": "^5.3.6",
     "ts-loader": "9.3.0",
     "typedoc": "0.28.15",
-    "typedoc-plugin-lsp-docs": "^0.0.1",
+    "typedoc-plugin-lsp-docs": "^0.0.2",
     "typescript": "5.9.3",
     "webpack": "5.94.0",
     "webpack-bundle-analyzer": "4.5.0",

+ 14 - 26
libs/src/LSPlugin.ts

@@ -699,15 +699,13 @@ export interface IEditorProxy extends Record<string, any> {
    * @param opts
    */
   insertBlock: (
-    srcBlock: BlockIdentity,
+    srcBlock: BlockIdentity | EntityID,
     content: string,
     opts?: Partial<{
       before: boolean
       sibling: boolean
       start: boolean
       end: boolean
-      isPageBlock: boolean
-      focus: boolean
       customUUID: string
       properties: {}
     }>
@@ -725,30 +723,20 @@ export interface IEditorProxy extends Record<string, any> {
   ) => Promise<Array<BlockEntity> | null>
 
   updateBlock: (
-    srcBlock: BlockIdentity,
+    srcBlock: BlockIdentity | EntityID,
     content: string,
     opts?: Partial<{ properties: {} }>
   ) => Promise<void>
 
-  removeBlock: (srcBlock: BlockIdentity) => Promise<void>
+  removeBlock: (srcBlock: BlockIdentity | EntityID) => Promise<void>
 
   getBlock: (
     srcBlock: BlockIdentity | EntityID,
     opts?: Partial<{ includeChildren: boolean }>
   ) => Promise<BlockEntity | null>
 
-  /**
-   * @example
-   *
-   * ```ts
-   *  logseq.Editor.setBlockCollapsed('uuid', true)
-   *  logseq.Editor.setBlockCollapsed('uuid', 'toggle')
-   * ```
-   * @param uuid
-   * @param opts
-   */
   setBlockCollapsed: (
-    uuid: BlockUUID,
+    srcBlock: BlockIdentity | EntityID,
     opts: { flag: boolean | 'toggle' } | boolean | 'toggle'
   ) => Promise<void>
 
@@ -782,7 +770,8 @@ export interface IEditorProxy extends Record<string, any> {
   getAllProperties: () => Promise<PageEntity[] | null>
   getTagObjects: (nameOrIdent: string) => Promise<BlockEntity[] | null>
   createTag: (tagName: string, opts?: Partial<{ uuid: string }>) => Promise<PageEntity | null>
-  getTag: (nameOrIdent: string) => Promise<PageEntity | null>
+  getTag: (nameOrIdent: string | EntityID) => Promise<PageEntity | null>
+  getTagsByName: (tagName: string) => Promise<Array<PageEntity> | null>
   addTagProperty: (tagId: BlockIdentity, propertyIdOrName: BlockIdentity) => Promise<void>
   removeTagProperty: (tagId: BlockIdentity, propertyIdOrName: BlockIdentity) => Promise<void>
   addTagExtends: (tagId: BlockIdentity, parentTagIdOrName: BlockIdentity) => Promise<void>
@@ -808,11 +797,11 @@ export interface IEditorProxy extends Record<string, any> {
   ) => Promise<BlockEntity | null>
 
   getPreviousSiblingBlock: (
-    srcBlock: BlockIdentity
+    srcBlock: BlockIdentity | EntityID
   ) => Promise<BlockEntity | null>
 
   getNextSiblingBlock: (
-    srcBlock: BlockIdentity
+    srcBlock: BlockIdentity | EntityID
   ) => Promise<BlockEntity | null>
 
   moveBlock: (
@@ -845,17 +834,15 @@ export interface IEditorProxy extends Record<string, any> {
 
   // block property related APIs
   upsertBlockProperty: (
-    block: BlockIdentity,
+    block: BlockIdentity | EntityID,
     key: string,
     value: any
   ) => Promise<void>
 
-  removeBlockProperty: (block: BlockIdentity, key: string) => Promise<void>
-
-  getBlockProperty: (block: BlockIdentity, key: string) => Promise<BlockEntity | unknown>
-
-  getBlockProperties: (block: BlockIdentity) => Promise<Record<string, any> | null>
-  getPageProperties: (page: PageIdentity) => Promise<Record<string, any> | null>
+  removeBlockProperty: (block: BlockIdentity | EntityID, key: string) => Promise<void>
+  getBlockProperty: (block: BlockIdentity | EntityID, key: string) => Promise<BlockEntity | null>
+  getBlockProperties: (block: BlockIdentity | EntityID) => Promise<Record<string, any> | null>
+  getPageProperties: (page: PageIdentity | EntityID) => Promise<Record<string, any> | null>
 
   scrollToBlockInPage: (
     pageName: BlockPageName,
@@ -864,6 +851,7 @@ export interface IEditorProxy extends Record<string, any> {
   ) => void
 
   openInRightSidebar: (id: BlockUUID | EntityID) => void
+  openPDFViewer: (assetBlockIdOrFileUrl: string | EntityID) => Promise<void>
 
   /**
    * @example https://github.com/logseq/logseq-plugin-samples/tree/master/logseq-a-translator

+ 8 - 0
src/main/frontend/components/property/value.cljs

@@ -1285,6 +1285,13 @@
      (fn []
        #(set-property-value! @*value))
      [])
+
+    (hooks/use-effect!
+     (fn []
+       (set-value! number-value)
+       #())
+     [number-value])
+
     [:div.ls-number.flex.flex-1.jtrigger
      {:ref *ref
       :on-click #(do
@@ -1297,6 +1304,7 @@
          :class (str "ls-number-input h-6 px-0 py-0 border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 text-base"
                      (when table-view? " text-sm"))
          :value value
+         :type "number"
          :on-change (fn [e]
                       (set-value! (util/evalue e))
                       (reset! *value (util/evalue e)))

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

@@ -135,6 +135,7 @@
 (def ^:export set_block_collapsed api-editor/set_block_collapsed)
 (def ^:export update_block api-editor/update_block)
 (def ^:export upsert_block_property api-editor/upsert_block_property)
+(def ^:export open_pdf_viewer api-editor/open_pdf_viewer)
 
 ;; ui
 (def ^:export show_msg sdk-ui/-show_msg)
@@ -203,6 +204,7 @@
 (def ^:export get_tag_objects db-based-api/get-tag-objects)
 (def ^:export create_tag db-based-api/create-tag)
 (def ^:export get_tag db-based-api/get-tag)
+(def ^:export get_tags_by_name db-based-api/get-tags-by-name)
 (def ^:export add_tag_extends db-based-api/add-tag-extends)
 (def ^:export remove_tag_extends db-based-api/remove-tag-extends)
 (def ^:export add_block_tag db-based-api/add-block-tag)

+ 29 - 17
src/main/logseq/api/db_based.cljs

@@ -7,6 +7,7 @@
             [clojure.walk :as walk]
             [datascript.core :as d]
             [frontend.db :as db]
+            [frontend.db.conn :as db-conn]
             [frontend.db.async :as db-async]
             [frontend.db.model :as db-model]
             [frontend.handler.common.page :as page-common-handler]
@@ -17,6 +18,7 @@
             [frontend.modules.layout.core]
             [frontend.state :as state]
             [frontend.util :as util]
+            [logseq.db.frontend.entity-util :as entity-util]
             [goog.object :as gobj]
             [logseq.api.block :as api-block]
             [logseq.db :as ldb]
@@ -220,9 +222,12 @@
    (when (text/namespace-page? title)
      (throw (ex-info "Tag title shouldn't include forward slash" {:title title})))
    (let [opts (bean/->clj opts)
+         custom-ident-namespace (:customIdentNamespace opts)
+         class-ident-namespace (or (some-> custom-ident-namespace (api-block/sanitize-user-property-name))
+                                   (api-block/resolve-class-prefix-for-db this))
          opts' (assoc opts
-                      :redirect? false
-                      :class-ident-namespace (api-block/resolve-class-prefix-for-db this))]
+                 :redirect? false
+                 :class-ident-namespace class-ident-namespace)]
      (p/let [tag (db-page-handler/<create-class! title opts')]
        (sdk-utils/result->js tag)))))
 
@@ -255,21 +260,28 @@
                                                 (:db/id extend))))
 
 (defn get-tag [class-uuid-or-ident-or-title]
-  (this-as
-   this
-   (let [title-or-ident (-> (if-not (string? class-uuid-or-ident-or-title)
-                              (str class-uuid-or-ident-or-title)
-                              class-uuid-or-ident-or-title)
-                            (string/replace #"^:+" ""))
-         eid (if (text/namespace-page? title-or-ident)
-               (keyword title-or-ident)
-               (if (util/uuid-string? title-or-ident)
-                 (when-let [id (sdk-utils/uuid-or-throw-error title-or-ident)]
-                   [:block/uuid id])
-                 (keyword (api-block/resolve-class-prefix-for-db this) title-or-ident)))
-         tag (db/entity eid)]
-     (when (ldb/class? tag)
-       (sdk-utils/result->js tag)))))
+  (this-as this
+    (let [eid (if (number? class-uuid-or-ident-or-title)
+                class-uuid-or-ident-or-title
+                (let [title-or-ident (-> (if-not (string? class-uuid-or-ident-or-title)
+                                           (str class-uuid-or-ident-or-title)
+                                           class-uuid-or-ident-or-title)
+                                         (string/replace #"^:+" ""))]
+                  (if (text/namespace-page? title-or-ident)
+                    (keyword title-or-ident)
+                    (if (util/uuid-string? title-or-ident)
+                      (when-let [id (sdk-utils/uuid-or-throw-error title-or-ident)]
+                        [:block/uuid id])
+                      (keyword (api-block/resolve-class-prefix-for-db this) title-or-ident)))))
+          tag (db/entity eid)]
+      (when (ldb/class? tag)
+        (sdk-utils/result->js tag)))))
+
+(defn get-tags-by-name [name]
+  (when-let [tags (some->> (entity-util/get-pages-by-name (db-conn/get-db) name)
+                           (map #(some-> % (first) (db/entity)))
+                           (filter ldb/class?))]
+    (sdk-utils/result->js tags)))
 
 (defn tag-add-property [tag-id property-id-or-name]
   (p/let [tag (db/get-case-page tag-id)

+ 119 - 124
src/main/logseq/api/editor.cljs

@@ -2,7 +2,6 @@
   "Editor related APIs"
   (:require [cljs-bean.core :as bean]
             [cljs.reader]
-            [clojure.string :as string]
             [frontend.commands :as commands]
             [frontend.config :as config]
             [frontend.date :as date]
@@ -17,6 +16,8 @@
             [frontend.handler.page :as page-handler]
             [frontend.handler.property :as property-handler]
             [frontend.handler.shell :as shell]
+            [frontend.handler.assets :as assets-handler]
+            [frontend.extensions.pdf.assets :as pdf-assets]
             [frontend.modules.layout.core]
             [frontend.modules.outliner.tree :as outliner-tree]
             [frontend.state :as state]
@@ -27,6 +28,7 @@
             [logseq.api.block :as api-block]
             [logseq.api.db-based :as db-based-api]
             [logseq.common.util.date-time :as date-time-util]
+            [logseq.common.path :as path]
             [logseq.db :as ldb]
             [logseq.outliner.core :as outliner-core]
             [logseq.sdk.core]
@@ -192,60 +194,46 @@
     block))
 
 (defn insert_block
-  [block-uuid-or-page-name content ^js opts]
+  [id content ^js opts]
   (this-as this
-           (when (string/blank? block-uuid-or-page-name)
-             (throw (js/Error. "Page title or block UUID shouldn't be empty.")))
-
-           (p/let [block? (util/uuid-string? (str block-uuid-or-page-name))
-                   block (<get-block (str block-uuid-or-page-name))]
-             (if (and block? (not block))
-               (throw (js/Error. "Block not exists"))
-               (p/let [{:keys [before start end sibling focus customUUID properties autoOrderedList schema]} (bean/->clj opts)
-                       [page-name block-uuid] (if (util/uuid-string? block-uuid-or-page-name)
-                                                [nil (uuid block-uuid-or-page-name)]
-                                                [block-uuid-or-page-name nil])
-                       page-name (when page-name (util/page-name-sanity-lc page-name))
-                       _ (when (and page-name
-                                    (nil? (ldb/get-page (db/get-db) page-name)))
-                           (page-handler/<create! block-uuid-or-page-name {}))
-                       custom-uuid (or customUUID (:id properties))
-                       custom-uuid (when custom-uuid (sdk-utils/uuid-or-throw-error custom-uuid))
-                       edit-block? (if (nil? focus) true focus)
-                       _ (when (and custom-uuid (db-model/query-block-by-uuid custom-uuid))
-                           (throw (js/Error.
-                                   (util/format "Custom block UUID already exists (%s)." custom-uuid))))
-                       block-uuid' (if (and (not sibling) before block-uuid)
-                                     (let [block (db/entity [:block/uuid block-uuid])
-                                           first-child (ldb/get-first-child (db/get-db) (:db/id block))]
-                                       (if first-child
-                                         (:block/uuid first-child)
-                                         block-uuid))
-                                     block-uuid)
-                       insert-at-first-child? (not= block-uuid' block-uuid)
-                       [sibling? before?] (if insert-at-first-child?
-                                            [true true]
-                                            [sibling before])
-                       db-based? (config/db-based-graph?)
-                       before? (if (and (false? sibling?) before? (not insert-at-first-child?))
-                                 false
-                                 before?)
-                       opts' {:block-uuid block-uuid'
-                              :sibling? sibling?
-                              :before? before?
-                              :start? start
-                              :end? end
-                              :edit-block? edit-block?
-                              :page page-name
-                              :custom-uuid custom-uuid
-                              :ordered-list? (if (boolean? autoOrderedList) autoOrderedList false)
-                              :properties (when (not db-based?)
-                                            (merge properties
-                                                   (when custom-uuid {:id custom-uuid})))}]
-                 (if db-based?
-                   (db-based-api/insert-block this content properties schema opts')
-                   (p/let [new-block (editor-handler/api-insert-new-block! content opts')]
-                     (bean/->js (sdk-utils/normalize-keyword-for-json new-block)))))))))
+    (p/let [block (<get-block id)]
+      (when-let [block-uuid (:block/uuid block)]
+        (p/let [{:keys [before start end sibling customUUID properties autoOrderedList schema]} (bean/->clj opts)
+                custom-uuid (or customUUID (:id properties))
+                custom-uuid (when custom-uuid (sdk-utils/uuid-or-throw-error custom-uuid))
+                _ (when (and custom-uuid (db-model/query-block-by-uuid custom-uuid))
+                    (throw (js/Error.
+                            (util/format "Custom block UUID already exists (%s)." custom-uuid))))
+                block-uuid' (if (and (not sibling) before block-uuid)
+                              (let [block (db/entity [:block/uuid block-uuid])
+                                    first-child (ldb/get-first-child (db/get-db) (:db/id block))]
+                                (if first-child
+                                  (:block/uuid first-child)
+                                  block-uuid))
+                              block-uuid)
+                insert-at-first-child? (not= block-uuid' block-uuid)
+                [sibling? before?] (if insert-at-first-child?
+                                     [true true]
+                                     [sibling before])
+                db-based? (config/db-based-graph?)
+                before? (if (and (false? sibling?) before? (not insert-at-first-child?))
+                          false
+                          before?)
+                opts' {:block-uuid block-uuid'
+                       :sibling? sibling?
+                       :before? before?
+                       :start? start
+                       :end? end
+                       :edit-block? false
+                       :custom-uuid custom-uuid
+                       :ordered-list? (if (boolean? autoOrderedList) autoOrderedList false)
+                       :properties (when (not db-based?)
+                                     (merge properties
+                                            (when custom-uuid {:id custom-uuid})))}]
+          (if db-based?
+            (db-based-api/insert-block this content properties schema opts')
+            (p/let [new-block (editor-handler/api-insert-new-block! content opts')]
+              (bean/->js (sdk-utils/normalize-keyword-for-json new-block)))))))))
 
 (def insert_batch_block
   (fn [block-uuid ^js batch-blocks-js ^js opts-js]
@@ -279,25 +267,25 @@
                          bean/->js))))))))))))
 
 (def remove_block
-  (fn [block-uuid ^js _opts]
-    (p/let [repo            (state/get-current-repo)
-            _ (<get-block block-uuid {:children? false})]
-      (editor-handler/delete-block-aux!
-       {:block/uuid (sdk-utils/uuid-or-throw-error block-uuid) :repo repo}))))
+  (fn [id ^js _opts]
+    (p/let [repo (state/get-current-repo)
+            block (<get-block id {:children? false})]
+      (when-let [block-uuid (:block/uuid block)]
+        (editor-handler/delete-block-aux!
+         {:block/uuid block-uuid :repo repo})))))
 
 (def update_block
-  (fn [block-uuid content ^js opts]
+  (fn [id content ^js opts]
     (this-as
      this
      (p/let [repo (state/get-current-repo)
              db-based? (config/db-based-graph?)
-             block (<get-block block-uuid {:children? false})
+             block (<get-block id {:children? false})
              opts' (bean/->clj opts)]
-       (when block
+       (when-let [block-uuid (:block/uuid block)]
          (if db-based?
            (db-based-api/update-block this block content opts')
-           (editor-handler/save-block! repo
-                                       (sdk-utils/uuid-or-throw-error block-uuid) content
+           (editor-handler/save-block! repo block-uuid content
                                        (if db-based? (dissoc opts' :properties) opts'))))))))
 
 (def move_block
@@ -335,9 +323,8 @@
       (get_block (:block/uuid block) opts))))
 
 (def get_previous_sibling_block
-  (fn [block-uuid ^js opts]
-    (p/let [id (sdk-utils/uuid-or-throw-error block-uuid)
-            block (<get-block id)
+  (fn [id ^js opts]
+    (p/let [block (<get-block id)
             ;; Load all children blocks
             _ (api-block/<sync-children-blocks! block)]
       (when block
@@ -345,9 +332,8 @@
           (get_block (:block/uuid sibling) opts))))))
 
 (def get_next_sibling_block
-  (fn [block-uuid ^js opts]
-    (p/let [id (sdk-utils/uuid-or-throw-error block-uuid)
-            block (<get-block id)
+  (fn [id ^js opts]
+    (p/let [block (<get-block id)
             ;; Load all children blocks
             _ (api-block/<sync-children-blocks! block)]
       (when block
@@ -355,11 +341,11 @@
           (get_block (:block/uuid sibling) opts))))))
 
 (def set_block_collapsed
-  (fn [block-uuid ^js opts]
-    (p/let [block-uuid (sdk-utils/uuid-or-throw-error block-uuid)
-            block (<get-block block-uuid {:children? false})]
+  (fn [id ^js opts]
+    (p/let [block (<get-block id {:children? false})]
       (when block
-        (let [opts (bean/->clj opts)
+        (let [block-uuid (:block/uuid block)
+              opts (bean/->clj opts)
               opts (if (or (string? opts) (boolean? opts)) {:flag opts} opts)
               {:keys [flag]} opts
               flag (if (= "toggle" flag)
@@ -467,64 +453,59 @@
 
 ;; block properties
 (defn upsert_block_property
-  [block-uuid key ^js value ^js options]
-  (this-as
-   this
-   (p/let [key' (api-block/sanitize-user-property-name key)
-           opts (bean/->clj options)
-           block-uuid (sdk-utils/uuid-or-throw-error block-uuid)
-           repo (state/get-current-repo)
-           block (<get-block block-uuid {:children? false})
-           db-based? (config/db-based-graph?)
-           value (bean/->clj value)]
-     (when block
-       (if db-based?
-         (db-based-api/upsert-block-property this block key' value opts)
-         (property-handler/set-block-property! repo block-uuid key' value))))))
+  [id key ^js value ^js options]
+  (this-as this
+    (p/let [key' (api-block/sanitize-user-property-name key)
+            opts (bean/->clj options)
+            repo (state/get-current-repo)
+            block (<get-block id {:children? false})
+            db-based? (config/db-based-graph?)
+            value (bean/->clj value)]
+      (when-let [block-uuid (:block/uuid block)]
+        (if db-based?
+          (db-based-api/upsert-block-property this block key' value opts)
+          (property-handler/set-block-property! repo block-uuid key' value))))))
 
 (defn remove_block_property
-  [block-uuid key]
+  [id key]
   (this-as this
-           (p/let [key (api-block/sanitize-user-property-name key)
-                   block-uuid (sdk-utils/uuid-or-throw-error block-uuid)
-                   _block (<get-block block-uuid {:children? false})
-                   db-based? (config/db-based-graph?)
-                   key-ns? (namespace (keyword key))
-                   key (if (and db-based? (not key-ns?))
-                         (api-block/get-db-ident-from-property-name key this)
-                         key)]
-             (property-handler/remove-block-property!
-              (state/get-current-repo)
-              block-uuid key))))
+    (p/let [block (<get-block id {:children? false})]
+      (when-let [block-uuid (:block/uuid block)]
+        (let [db-based? (config/db-based-graph?)
+              key (api-block/sanitize-user-property-name key)
+              key (if db-based?
+                    (api-block/get-db-ident-from-property-name key this)
+                    key)]
+          (property-handler/remove-block-property!
+            (state/get-current-repo)
+            block-uuid key))))))
 
 (defn get_block_property
-  [block-uuid key]
+  [id key]
   (this-as this
-           (p/let [block-uuid (sdk-utils/uuid-or-throw-error block-uuid)
-                   _block (<get-block block-uuid {:children? false})]
-             (when-let [properties (some-> block-uuid (db-model/get-block-by-uuid) (:block/properties))]
-               (when (seq properties)
-                 (let [property-name (api-block/sanitize-user-property-name key)
-                       ident (api-block/get-db-ident-from-property-name property-name this)
-                       property-value (or (get properties property-name)
-                                          (get properties (keyword property-name))
-                                          (get properties ident))
-                       property-value (if-let [property-id (:db/id property-value)]
-                                        (db/pull property-id) property-value)
-                       property-value (cond-> property-value
-                                        (map? property-value)
-                                        (assoc
-                                         :value (or (:logseq.property/value property-value)
-                                                    (:block/title property-value))
-                                         :ident ident))
-                       parsed-value (api-block/parse-property-json-value-if-need ident property-value)]
-                   (or parsed-value
-                       (bean/->js (sdk-utils/normalize-keyword-for-json property-value)))))))))
+    (p/let [block (<get-block id {:children? false})]
+      (when-let [properties (some-> block (:block/uuid) (db-model/get-block-by-uuid) (:block/properties))]
+        (when (seq properties)
+          (let [property-name (api-block/sanitize-user-property-name key)
+                ident (api-block/get-db-ident-from-property-name property-name this)
+                property-value (or (get properties property-name)
+                                 (get properties (keyword property-name))
+                                 (get properties ident))
+                property-value (if-let [property-id (:db/id property-value)]
+                                 (db/pull property-id) property-value)
+                property-value (cond-> property-value
+                                 (map? property-value)
+                                 (assoc
+                                   :value (or (:logseq.property/value property-value)
+                                            (:block/title property-value))
+                                   :ident ident))
+                parsed-value (api-block/parse-property-json-value-if-need ident property-value)]
+            (or parsed-value
+              (bean/->js (sdk-utils/normalize-keyword-for-json property-value)))))))))
 
 (def get_block_properties
-  (fn [block-uuid]
-    (p/let [block-uuid (sdk-utils/uuid-or-throw-error block-uuid)
-            block (<get-block block-uuid {:children? false})]
+  (fn [id]
+    (p/let [block (<get-block id {:children? false})]
       (when block
         (let [properties (if (config/db-based-graph?)
                            (api-block/into-readable-db-properties (:block/properties block))
@@ -536,3 +517,17 @@
   (p/let [page (<get-block id-or-page-name {:children? false})]
     (when-let [id (:block/uuid page)]
       (get_block_properties id))))
+
+(defn open_pdf_viewer
+  [block-identity-or-file-url]
+  (p/let [[block href] (if (and (string? block-identity-or-file-url)
+                                (or (path/protocol-url? block-identity-or-file-url)
+                                    (path/absolute? block-identity-or-file-url)))
+                         [nil block-identity-or-file-url]
+                         (p/let [block (<get-block block-identity-or-file-url {:children? false})]
+                           [block (if block
+                                    (util/format "../assets/%s.pdf" (:block/uuid block))
+                                    block-identity-or-file-url)]))
+          href' (assets-handler/<make-asset-url href)]
+    (when-let [current (pdf-assets/inflate-asset href {:block block :href href'})]
+      (state/set-current-pdf! current))))