Browse Source

enhance(api): plugin class with ident like `plugin.class.id/class-name` (#12200)

* enhance(api): plugin class with ident like `plugin.class.id/class-name`
* enhance(apis): remove support for namespace separator in create tag
* enhance(apis): get tag with ident or uuid
* fix(lint): remove unused vars
* fix(apis): sanitize user property name
* enhance(apis): get tag ex info
* chore: bump libs version
---------
Co-authored-by: charlie <[email protected]>
Tienson Qin 2 weeks ago
parent
commit
0a54e807bb

+ 5 - 4
deps/db/src/logseq/db/frontend/class.cljs

@@ -168,8 +168,9 @@
 (defn create-user-class-ident-from-name
   "Creates a class :db/ident for a default user namespace.
    NOTE: Only use this when creating a db-ident for a new class."
-  [db class-name]
-  (let [db-ident (db-ident/create-db-ident-from-name "user.class" class-name)]
+  [db class-name & {:keys [ident-namespace]}]
+  (let [ident-ns (or ident-namespace "user.class")
+        db-ident (db-ident/create-db-ident-from-name ident-ns class-name)]
     (if db
       (db-ident/ensure-unique-db-ident db db-ident)
       db-ident)))
@@ -177,9 +178,9 @@
 (defn build-new-class
   "Builds a new class with a unique :db/ident. Also throws exception for user
   facing messages when name is invalid"
-  [db page-m]
+  [db page-m & {:as option}]
   {:pre [(string? (:block/title page-m))]}
-  (let [db-ident (create-user-class-ident-from-name db (:block/title page-m))]
+  (let [db-ident (create-user-class-ident-from-name db (:block/title page-m) option)]
     (sqlite-util/build-new-class (assoc page-m :db/ident db-ident))))
 
 (defonce logseq-class "logseq.class")

+ 4 - 2
deps/db/src/logseq/db/frontend/db_ident.cljc

@@ -80,13 +80,15 @@
          :default          false)
      ;; Used for contexts where we want repeatable idents e.g. tests and CLIs
     (keyword user-namespace (normalize-ident-name-part name-string))
-    (let [suffix (str "-"
+    (let [plugin? (string/starts-with? user-namespace "plugin.class.")
+          suffix (str "-"
                       (rand-nth non-int-char-range)
                       (nano-id 7))]
       (keyword user-namespace
                (str
                 (normalize-ident-name-part name-string)
-                suffix)))))
+                (when-not plugin?
+                  suffix))))))
 
 (defn replace-db-ident-random-suffix
   [db-ident-kw new-suffix]

+ 8 - 5
deps/outliner/src/logseq/outliner/page.cljs

@@ -82,7 +82,7 @@
                              (assoc :real-outliner-op :rename-page)))
             true))))))
 
-(defn- build-page-tx [db properties page {:keys [whiteboard? class? tags]}]
+(defn- build-page-tx [db properties page {:keys [whiteboard? class? tags class-ident-namespace]}]
   (when (:block/uuid page)
     (let [type-tag (cond class? :logseq.class/Tag
                          whiteboard? :logseq.class/Whiteboard
@@ -117,7 +117,7 @@
                           [k v])))
                 (into {})))]
       (cond-> (if class?
-                [(merge (db-class/build-new-class db page')
+                [(merge (db-class/build-new-class db page' {:ident-namespace class-ident-namespace})
                         ;; FIXME: new pages shouldn't have db/ident but converting property to tag still relies on this
                         (select-keys page' [:db/ident]))
                  [:db/retract [:block/uuid (:block/uuid page)] :block/tags :logseq.class/Page]]
@@ -234,7 +234,7 @@
   [db title*
    {uuid' :uuid
     :keys [tags properties persist-op? whiteboard?
-           class? today-journal? split-namespace?]
+           class? today-journal? split-namespace? class-ident-namespace]
     :or   {properties               nil
            persist-op?              true}
     :as options}]
@@ -263,7 +263,10 @@
                    (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]))
+          (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))
+                                                            {: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
@@ -289,7 +292,7 @@
               (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]))
+                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')

+ 1 - 1
libs/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@logseq/libs",
-  "version": "0.2.7",
+  "version": "0.2.8",
   "description": "Logseq SDK libraries",
   "main": "dist/lsplugin.user.js",
   "typings": "index.d.ts",

+ 3 - 1
libs/src/LSPlugin.ts

@@ -232,6 +232,7 @@ export interface PageEntity {
   children?: Array<PageEntity>
   properties?: Record<string, any>
   journalDay?: number
+  ident?: string
 
   [key: string]: unknown
 }
@@ -779,8 +780,9 @@ export interface IEditorProxy extends Record<string, any> {
   getAllPages: (repo?: string) => Promise<PageEntity[] | null>
   getAllTags: () => Promise<PageEntity[] | null>
   getAllProperties: () => Promise<PageEntity[] | null>
-  getTagObjects: (PageIdentity) => Promise<BlockEntity[] | null>
+  getTagObjects: (nameOrIdent: string) => Promise<BlockEntity[] | null>
   createTag: (tagName: string, opts?: Partial<{ uuid: string }>) => Promise<PageEntity | null>
+  getTag: (nameOrIdent: string) => Promise<PageEntity | null>
   addTagProperty: (tagId: BlockIdentity, propertyIdOrName: BlockIdentity) => Promise<void>
   removeTagProperty: (tagId: BlockIdentity, propertyIdOrName: BlockIdentity) => Promise<void>
   addBlockTag: (blockId: BlockIdentity, tagId: BlockIdentity) => Promise<void>

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

@@ -201,6 +201,7 @@
 (def ^:export get_all_properties db-based-api/get-all-properties)
 (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 add_block_tag db-based-api/add-block-tag)
 (def ^:export remove_block_tag db-based-api/remove-block-tag)
 (def ^:export add_tag_property db-based-api/tag-add-property)

+ 11 - 4
src/main/logseq/api/block.cljs

@@ -17,16 +17,14 @@
             [logseq.sdk.utils :as sdk-utils]))
 
 (def plugin-property-prefix "plugin.property.")
+(def plugin-class-prefix "plugin.class.")
 
 (defn sanitize-user-property-name
   [k]
   (if (string? k)
     (-> k (string/trim)
         (string/replace " " "")
-        (string/replace #"^[:_\s]+" "")
-        (#(cond-> %
-            (not (string/includes? % "/"))
-            (string/lower-case))))
+        (string/replace #"^[:_\s]+" ""))
     (str k)))
 
 (defn get-sanitized-plugin-id
@@ -60,6 +58,15 @@
       (let [plugin-ns (resolve-property-prefix-for-db plugin)]
         (keyword plugin-ns (db-ident/normalize-ident-name-part property-name'))))))
 
+(defn resolve-class-prefix-for-db
+  [^js plugin]
+  (let [plugin-id (get-sanitized-plugin-id plugin)]
+    (when-not plugin-id
+      (js/console.error "Can't get current plugin id")
+      (throw (ex-info "Can't get current plugin id"
+                      {:plugin plugin})))
+    (str plugin-class-prefix plugin-id)))
+
 (defn plugin-property-key?
   [ident]
   (and (qualified-keyword? ident)

+ 31 - 9
src/main/logseq/api/db_based.cljs

@@ -5,6 +5,7 @@
             [clojure.string :as string]
             [clojure.walk :as walk]
             [datascript.core :as d]
+            [logseq.graph-parser.text :as text]
             [frontend.db :as db]
             [frontend.db.async :as db-async]
             [frontend.db.model :as db-model]
@@ -204,15 +205,36 @@
         (sdk-utils/result->js result)))))
 
 (defn create-tag [title ^js opts]
-  (let [opts (bean/->clj opts)]
-    (p/let [repo (state/get-current-repo)
-            tag (db-page-handler/<create-class!
-                 title
-                 (-> opts
-                     (sdk-utils/with-custom-uuid)
-                     (assoc :redirect? false)))
-            tag (db-async/<get-block repo (:db/id tag) {:children? false})]
-      (when tag
+  (this-as
+    this
+    (when-not (string? title)
+      (throw (ex-info "Tag title should be a string" {:title title})))
+    (when (string/blank? title)
+      (throw (ex-info "Tag title shouldn't be empty" {:title title})))
+    (when (text/namespace-page? title)
+      (throw (ex-info "Tag title shouldn't include forward slash" {:title title})))
+    (let [opts (bean/->clj opts)
+          opts' (assoc opts
+                  :redirect? false
+                  :class-ident-namespace (api-block/resolve-class-prefix-for-db this))]
+      (p/let [tag (db-page-handler/<create-class! title opts')]
+        (sdk-utils/result->js tag)))))
+
+(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)))))
 
 (defn tag-add-property [tag-id property-id-or-name]

+ 0 - 6
src/main/logseq/sdk/utils.cljs

@@ -101,12 +101,6 @@
       normalize-keyword-for-json
       bean/->js))
 
-(defn with-custom-uuid [opts]
-  (let [custom-uuid (or (:customUUID opts) (:uuid opts))]
-    (cond-> opts
-            (util/uuid-string? custom-uuid)
-            (assoc :uuid (uuid custom-uuid)))))
-
 (def ^:export to-clj bean/->clj)
 (def ^:export jsx-to-clj jsx->clj)
 (def ^:export to-js bean/->js)