api.cljs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. (ns ^:no-doc logseq.api
  2. (:require [frontend.db :as db]
  3. [frontend.db.model :as db-model]
  4. [frontend.db.utils :as db-utils]
  5. [frontend.handler.block :as block-handler]
  6. [frontend.handler.editor :as editor-handler]
  7. [frontend.handler.dnd :as editor-dnd-handler]
  8. [frontend.modules.outliner.tree :as outliner-tree]
  9. [frontend.util :as util]
  10. [electron.ipc :as ipc]
  11. [promesa.core :as p]
  12. [sci.core :as sci]
  13. [lambdaisland.glogi :as log]
  14. [camel-snake-kebab.core :as csk]
  15. [cljs-bean.core :as bean]
  16. [frontend.state :as state]
  17. [frontend.components.plugins :as plugins]
  18. [frontend.handler.plugin :as plugin-handler]
  19. [frontend.handler.notification :as notification]
  20. [datascript.core :as d]
  21. [medley.core :as medley]
  22. [frontend.fs :as fs]
  23. [clojure.string :as string]
  24. [clojure.walk :as walk]
  25. [cljs.reader]
  26. [reitit.frontend.easy :as rfe]
  27. [frontend.db.query-dsl :as query-dsl]))
  28. ;; helpers
  29. (defn- normalize-keyword-for-json
  30. [input]
  31. (when input
  32. (walk/postwalk
  33. (fn [a]
  34. (cond
  35. (keyword? a) (csk/->camelCase (name a))
  36. (uuid? a) (str a)
  37. :else a)) input)))
  38. (defn- parse-hiccup-ui
  39. [input]
  40. (when (string? input)
  41. (try
  42. (sci/eval-string input {:preset :termination-safe})
  43. (catch js/Error e
  44. (js/console.error "[parse hiccup error]" e) input))))
  45. ;; base
  46. (def ^:export get_user_configs
  47. (fn []
  48. (bean/->js
  49. (normalize-keyword-for-json
  50. {:preferred-language (:preferred-language @state/state)
  51. :preferred-format (state/get-preferred-format)
  52. :preferred-workflow (state/get-preferred-workflow)
  53. :preferred-todo (state/get-preferred-todo)
  54. :current-graph (state/get-current-repo)
  55. :me (state/get-me)}))))
  56. (def ^:export show_themes
  57. (fn []
  58. (plugins/open-select-theme!)))
  59. (def ^:export set_theme_mode
  60. (fn [mode]
  61. (state/set-theme! (if (= mode "light") "white" "dark"))))
  62. (def ^:export load_plugin_config
  63. (fn [path]
  64. (fs/read-file "" (util/node-path.join path "package.json"))))
  65. (def ^:export load_plugin_readme
  66. (fn [path]
  67. (fs/read-file "" (util/node-path.join path "readme.md"))))
  68. (def ^:export save_plugin_config
  69. (fn [path ^js data]
  70. (let [repo ""
  71. path (util/node-path.join path "package.json")]
  72. (fs/write-file! repo "" path (js/JSON.stringify data nil 2) {:skip-mtime? true}))))
  73. (def ^:export write_user_tmp_file
  74. (fn [file content]
  75. (p/let [repo ""
  76. path (plugin-handler/get-ls-dotdir-root)
  77. path (util/node-path.join path "tmp")
  78. exist? (fs/file-exists? path "")
  79. _ (when-not exist? (fs/mkdir! path))
  80. path (util/node-path.join path file)
  81. _ (fs/write-file! repo "" path content {:skip-mtime? true})]
  82. path)))
  83. (def ^:export load_user_preferences
  84. (fn []
  85. (p/let [repo ""
  86. path (plugin-handler/get-ls-dotdir-root)
  87. path (util/node-path.join path "preferences.json")
  88. _ (fs/create-if-not-exists repo "" path)
  89. json (fs/read-file "" path)
  90. json (if (string/blank? json) "{}" json)]
  91. (js/JSON.parse json))))
  92. (def ^:export save_user_preferences
  93. (fn [^js data]
  94. (when data
  95. (p/let [repo ""
  96. path (plugin-handler/get-ls-dotdir-root)
  97. path (util/node-path.join path "preferences.json")]
  98. (fs/write-file! repo "" path (js/JSON.stringify data nil 2) {:skip-mtime? true})))))
  99. (def ^:export load_plugin_user_settings
  100. (fn [key]
  101. (p/let [repo ""
  102. path (plugin-handler/get-ls-dotdir-root)
  103. exist? (fs/file-exists? path "settings")
  104. _ (when-not exist? (fs/mkdir! (util/node-path.join path "settings")))
  105. path (util/node-path.join path "settings" (str key ".json"))
  106. _ (fs/create-if-not-exists repo "" path "{}")
  107. json (fs/read-file "" path)]
  108. [path (js/JSON.parse json)])))
  109. (def ^:export save_plugin_user_settings
  110. (fn [key ^js data]
  111. (p/let [repo ""
  112. path (plugin-handler/get-ls-dotdir-root)
  113. path (util/node-path.join path "settings" (str key ".json"))]
  114. (fs/write-file! repo "" path (js/JSON.stringify data nil 2) {:skip-mtime? true}))))
  115. (def ^:export register_plugin_slash_command
  116. (fn [pid ^js cmd-actions]
  117. (when-let [[cmd actions] (bean/->clj cmd-actions)]
  118. (plugin-handler/register-plugin-slash-command
  119. pid [cmd (mapv #(into [(keyword (first %))]
  120. (rest %)) actions)]))))
  121. (def ^:export register_plugin_simple_command
  122. (fn [pid ^js cmd-action]
  123. (when-let [[cmd action] (bean/->clj cmd-action)]
  124. (plugin-handler/register-plugin-simple-command
  125. pid cmd (assoc action 0 (keyword (first action)))))))
  126. ;; app
  127. (def ^:export push_state
  128. (fn [^js k ^js params]
  129. (rfe/push-state
  130. (keyword k) (bean/->clj params))))
  131. (def ^:export replace_state
  132. (fn [^js k ^js params]
  133. (rfe/replace-state
  134. (keyword k) (bean/->clj params))))
  135. ;; editor
  136. (def ^:export get_current_block
  137. (fn []
  138. (let [block (state/get-edit-block)
  139. block (or block (state/get-last-edit-block))
  140. block (and block (db-utils/pull (:db/id block)))]
  141. (bean/->js (normalize-keyword-for-json block)))))
  142. (def ^:export get_edit_block_content
  143. (fn []
  144. (state/get-edit-content)))
  145. (def ^:export get_current_page
  146. (fn []
  147. (when-let [page (state/get-current-page)]
  148. (when-let [page (db-model/get-page page)]
  149. (bean/->js (normalize-keyword-for-json (db-utils/pull (:db/id page))))))))
  150. (def ^:export insert_block
  151. (fn [block-uuid-or-page-name content ^js opts]
  152. (let [{:keys [before sibling isPageBlock props]} (bean/->clj opts)
  153. page-name (and isPageBlock block-uuid-or-page-name)
  154. block-uuid (if isPageBlock nil (medley/uuid block-uuid-or-page-name))
  155. new-block (editor-handler/api-insert-new-block!
  156. content {:block-uuid block-uuid :sibling? sibling :page page-name})]
  157. (bean/->js (normalize-keyword-for-json new-block)))))
  158. (def ^:export remove_block
  159. (fn [block-uuid ^js opts]
  160. (let [{:keys [includeChildren]} (bean/->clj opts)
  161. repo (state/get-current-repo)]
  162. (editor-handler/delete-block-aux!
  163. {:block/uuid (medley/uuid block-uuid) :repo repo} includeChildren))))
  164. (def ^:export update_block
  165. (fn [block-uuid content ^js opts]
  166. (let [opts (and opts (bean/->clj opts))
  167. repo (state/get-current-repo)
  168. editing? (string/ends-with? (state/get-edit-input-id) block-uuid)]
  169. (if editing?
  170. (state/set-edit-content! (state/get-edit-input-id) content)
  171. (editor-handler/save-block! repo (medley/uuid block-uuid) content)))))
  172. (def ^:export move_block
  173. (fn [src-block-uuid target-block-uuid ^js opts]
  174. (let [{:keys [before children]} (bean/->clj opts)
  175. top? (boolean before)
  176. nested? (boolean children)
  177. src-block-uuid (db-model/query-block-by-uuid (medley/uuid src-block-uuid))
  178. target-block-uuid (db-model/query-block-by-uuid (medley/uuid target-block-uuid))]
  179. (editor-dnd-handler/move-block src-block-uuid target-block-uuid top? nested?))))
  180. (def ^:export get_block
  181. (fn [id-or-uuid ^js opts]
  182. (when-let [block (cond
  183. (number? id-or-uuid) (db-utils/pull id-or-uuid)
  184. (string? id-or-uuid) (db-model/query-block-by-uuid id-or-uuid))]
  185. (when-let [uuid (:block/uuid block)]
  186. (let [{:keys [includeChildren]} (bean/->clj opts)
  187. block (if (not includeChildren) block (first (outliner-tree/blocks->vec-tree [block] uuid)))]
  188. (bean/->js (normalize-keyword-for-json block)))))))
  189. (def ^:export upsert_block_property
  190. (fn [block-uuid key value]
  191. (editor-handler/set-block-property! (medley/uuid block-uuid) key value)))
  192. (def ^:export remove_block_property
  193. (fn [block-uuid key]
  194. (editor-handler/remove-block-property! (medley/uuid block-uuid) key)))
  195. (def ^:export get_block_property
  196. (fn [block-uuid key]
  197. (when-let [block (db-model/query-block-by-uuid block-uuid)]
  198. (get (:block/properties block) (keyword key)))))
  199. (def ^:export get_block_properties
  200. (fn [block-uuid]
  201. (when-let [block (db-model/query-block-by-uuid block-uuid)]
  202. (bean/->js (normalize-keyword-for-json (:block/properties block))))))
  203. (def ^:export get_current_page_blocks_tree
  204. (fn []
  205. (when-let [page (state/get-current-page)]
  206. (let [blocks (db-model/get-page-blocks-no-cache page)
  207. blocks (outliner-tree/blocks->vec-tree blocks page)
  208. ;; clean key
  209. blocks (normalize-keyword-for-json blocks)]
  210. (bean/->js blocks)))))
  211. (def ^:export get_page_blocks_tree
  212. (fn [page-name]
  213. (when-let [_ (db-model/get-page page-name)]
  214. (let [blocks (db-model/get-page-blocks-no-cache page-name)
  215. blocks (outliner-tree/blocks->vec-tree blocks page-name)
  216. blocks (normalize-keyword-for-json blocks)]
  217. (bean/->js blocks)))))
  218. ;; db
  219. (defn ^:export q
  220. [query-string]
  221. (when-let [repo (state/get-current-repo)]
  222. (when-let [conn (db/get-conn repo)]
  223. (when-let [result (query-dsl/query repo query-string)]
  224. (clj->js @result)))))
  225. (defn ^:export datascript_query
  226. [query & inputs]
  227. (when-let [repo (state/get-current-repo)]
  228. (when-let [conn (db/get-conn repo)]
  229. (let [query (cljs.reader/read-string query)
  230. result (apply d/q query conn inputs)]
  231. (clj->js result)))))
  232. (def ^:export custom_query db/custom-query)
  233. ;; helpers
  234. (defn ^:export show_msg
  235. ([content] (show_msg content :success))
  236. ([content status] (let [hiccup? (and (string? content) (string/starts-with? (string/triml content) "[:"))
  237. content (if hiccup? (parse-hiccup-ui content) content)]
  238. (notification/show! content (keyword status)))))