config.cljs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. (ns frontend.config
  2. "App config and fns built on top of configuration"
  3. (:require [clojure.set :as set]
  4. [clojure.string :as string]
  5. [frontend.mobile.util :as mobile-util]
  6. [frontend.state :as state]
  7. [frontend.util :as util]
  8. [goog.crypt :as crypt]
  9. [goog.crypt.Md5]
  10. [logseq.common.config :as common-config]
  11. [logseq.common.path :as path]
  12. [logseq.common.util :as common-util]
  13. [logseq.db.sqlite.util :as sqlite-util]
  14. [shadow.resource :as rc]))
  15. (goog-define DEV-RELEASE false)
  16. (defonce dev-release? DEV-RELEASE)
  17. (defonce dev? ^boolean (or dev-release? goog.DEBUG))
  18. (defonce publishing? common-config/PUBLISHING)
  19. (goog-define REVISION "unknown")
  20. (defonce revision REVISION)
  21. (goog-define ENABLE-FILE-SYNC-PRODUCTION false)
  22. ;; this is a feature flag to enable the account tab
  23. ;; when it launches (when pro plan launches) it should be removed
  24. (def ENABLE-SETTINGS-ACCOUNT-TAB false)
  25. (if ENABLE-FILE-SYNC-PRODUCTION
  26. (do (def FILE-SYNC-PROD? true)
  27. (def LOGIN-URL
  28. "https://logseq-prod.auth.us-east-1.amazoncognito.com/login?client_id=3c7np6bjtb4r1k1bi9i049ops5&response_type=code&scope=email+openid+phone&redirect_uri=logseq%3A%2F%2Fauth-callback")
  29. (def API-DOMAIN "api.logseq.com")
  30. (def WS-URL "wss://ws.logseq.com/file-sync?graphuuid=%s")
  31. (def COGNITO-IDP "https://cognito-idp.us-east-1.amazonaws.com/")
  32. (def COGNITO-CLIENT-ID "69cs1lgme7p8kbgld8n5kseii6")
  33. (def REGION "us-east-1")
  34. (def USER-POOL-ID "us-east-1_dtagLnju8")
  35. (def IDENTITY-POOL-ID "us-east-1:d6d3b034-1631-402b-b838-b44513e93ee0")
  36. (def OAUTH-DOMAIN "logseq-prod.auth.us-east-1.amazoncognito.com")
  37. (def CONNECTIVITY-TESTING-S3-URL "https://logseq-connectivity-testing-prod.s3.us-east-1.amazonaws.com/logseq-connectivity-testing"))
  38. (do (def FILE-SYNC-PROD? false)
  39. (def LOGIN-URL
  40. "https://logseq-test2.auth.us-east-2.amazoncognito.com/login?client_id=3ji1a0059hspovjq5fhed3uil8&response_type=code&scope=email+openid+phone&redirect_uri=logseq%3A%2F%2Fauth-callback")
  41. (def API-DOMAIN "api-dev.logseq.com")
  42. (def WS-URL "wss://ws-dev.logseq.com/file-sync?graphuuid=%s")
  43. (def COGNITO-IDP "https://cognito-idp.us-east-2.amazonaws.com/")
  44. (def COGNITO-CLIENT-ID "1qi1uijg8b6ra70nejvbptis0q")
  45. (def REGION "us-east-2")
  46. (def USER-POOL-ID "us-east-2_kAqZcxIeM")
  47. (def IDENTITY-POOL-ID "us-east-2:cc7d2ad3-84d0-4faf-98fe-628f6b52c0a5")
  48. (def OAUTH-DOMAIN "logseq-test2.auth.us-east-2.amazoncognito.com")
  49. (def CONNECTIVITY-TESTING-S3-URL "https://logseq-connectivity-testing-prod.s3.us-east-1.amazonaws.com/logseq-connectivity-testing")))
  50. (goog-define ENABLE-RTC-SYNC-PRODUCTION false)
  51. (if ENABLE-RTC-SYNC-PRODUCTION
  52. (def RTC-WS-URL "wss://ws.logseq.com/rtc-sync?token=%s")
  53. (def RTC-WS-URL "wss://ws-dev.logseq.com/rtc-sync?token=%s"))
  54. ;; Feature flags
  55. ;; =============
  56. (goog-define ENABLE-PLUGINS true)
  57. (defonce feature-plugin-system-on? ENABLE-PLUGINS)
  58. ;; Desktop only as other platforms requires better understanding of their
  59. ;; multi-graph workflows and optimal place for a "global" dir
  60. (def global-config-enabled? util/electron?)
  61. ;; User level configuration for whether plugins are enabled
  62. (defonce lsp-enabled?
  63. (and util/plugin-platform?
  64. (not (false? feature-plugin-system-on?))
  65. (state/lsp-enabled?-or-theme)))
  66. (defn plugin-config-enabled?
  67. []
  68. (and lsp-enabled? (global-config-enabled?)))
  69. ;; :TODO: How to do this?
  70. ;; (defonce desktop? ^boolean goog.DESKTOP)
  71. ;; ============
  72. (def app-name common-config/app-name)
  73. (def website
  74. (if dev?
  75. "http://localhost:3000"
  76. (util/format "https://%s.com" app-name)))
  77. ;; FIXME:
  78. (def app-website
  79. (if dev?
  80. "http://localhost:3001"
  81. (util/format "https://%s.com" app-name)))
  82. (def asset-domain (util/format "https://asset.%s.com"
  83. app-name))
  84. ;; TODO: Remove this, switch to lazy loader
  85. (defn asset-uri
  86. [path]
  87. (cond
  88. publishing?
  89. path
  90. (util/file-protocol?)
  91. (string/replace path "/static/" "./")
  92. :else
  93. (if dev? path
  94. (str asset-domain path))))
  95. (def markup-formats
  96. #{:org :md :markdown :asciidoc :adoc :rst})
  97. (def doc-formats
  98. #{:doc :docx :xls :xlsx :ppt :pptx :one :pdf :epub})
  99. (def image-formats
  100. #{:png :jpg :jpeg :bmp :gif :webp :svg :heic})
  101. (def audio-formats
  102. #{:mp3 :ogg :mpeg :wav :m4a :flac :wma :aac})
  103. (def video-formats
  104. #{:mp4 :webm :mov :flv :avi :mkv})
  105. (def media-formats (set/union (common-config/img-formats) audio-formats video-formats))
  106. (defn extname-of-supported?
  107. ([input] (extname-of-supported?
  108. input
  109. [image-formats doc-formats audio-formats
  110. video-formats markup-formats
  111. (common-config/text-formats)]))
  112. ([input formats]
  113. (when-let [input (some->
  114. (cond-> input
  115. (and (string? input)
  116. (not (string/blank? input)))
  117. (string/replace-first "." ""))
  118. (util/safe-lower-case)
  119. (keyword))]
  120. (boolean
  121. (some
  122. (fn [s]
  123. (contains? s input))
  124. formats)))))
  125. (defn ext-of-video?
  126. ([s] (ext-of-video? s true))
  127. ([s html5?]
  128. (when-let [s (and (string? s) (util/get-file-ext s))]
  129. (let [video-formats' (cond-> video-formats
  130. html5? (disj :mkv))]
  131. (extname-of-supported? s [video-formats'])))))
  132. (defn ext-of-audio?
  133. ([s] (ext-of-audio? s true))
  134. ([s html5?]
  135. (when-let [s (and (string? s) (util/get-file-ext s))]
  136. (let [audio-formats' (cond-> audio-formats
  137. html5? (disj :wma :ogg))]
  138. (extname-of-supported? s [audio-formats'])))))
  139. (defn ext-of-image?
  140. [s]
  141. (when-let [s (and (string? s) (util/get-file-ext s))]
  142. (extname-of-supported? s [image-formats])))
  143. (def mobile?
  144. "Triggering condition: Mobile phones
  145. *** Warning!!! ***
  146. For UX logic only! Don't use for FS logic
  147. iPad / Android Pad doesn't trigger!
  148. Same as config/mobile?"
  149. (when-not util/node-test?
  150. (util/safe-re-find #"Mobi" js/navigator.userAgent)))
  151. ;; TODO: protocol design for future formats support
  152. (defn get-block-pattern
  153. [format]
  154. (common-config/get-block-pattern (or format (state/get-preferred-format))))
  155. (defn get-hr
  156. [format]
  157. (let [format (or format (keyword (state/get-preferred-format)))]
  158. (case format
  159. :org
  160. "-----"
  161. :markdown
  162. "---"
  163. "")))
  164. (defn get-bold
  165. [format]
  166. (let [format (or format (keyword (state/get-preferred-format)))]
  167. (case format
  168. :org
  169. "*"
  170. :markdown
  171. "**"
  172. "")))
  173. (defn get-italic
  174. [format]
  175. (let [format (or format (keyword (state/get-preferred-format)))]
  176. (case format
  177. :org
  178. "/"
  179. :markdown
  180. "*"
  181. "")))
  182. (defn get-underline
  183. [format]
  184. (let [format (or format (keyword (state/get-preferred-format)))]
  185. (case format
  186. :org
  187. "_"
  188. :markdown ;; no underline for markdown
  189. ""
  190. "")))
  191. (defn get-strike-through
  192. [format]
  193. (let [format (or format (keyword (state/get-preferred-format)))]
  194. (case format
  195. :org
  196. "+"
  197. :markdown
  198. "~~"
  199. "")))
  200. (defn get-highlight
  201. [format]
  202. (case format
  203. :org
  204. "^^"
  205. :markdown
  206. "=="
  207. ""))
  208. (defn get-code
  209. [format]
  210. (let [format (or format (keyword (state/get-preferred-format)))]
  211. (case format
  212. :org
  213. "~"
  214. :markdown
  215. "`"
  216. "")))
  217. (defn get-empty-link-and-forward-pos
  218. [format]
  219. (case format
  220. :org
  221. ["[[][]]" 2]
  222. :markdown
  223. ["[]()" 1]
  224. ["" 0]))
  225. (defn link-format
  226. [format label link]
  227. (if (not-empty label)
  228. (case format
  229. :org
  230. (util/format "[[%s][%s]]" link label)
  231. :markdown
  232. (util/format "[%s](%s)" label link))
  233. link))
  234. (defn with-default-link
  235. [format link]
  236. (case format
  237. :org
  238. [(util/format "[[%s][]]" link)
  239. (+ 4 (count link))]
  240. :markdown
  241. [(util/format "[](%s)" link)
  242. 1]
  243. ["" 0]))
  244. (defn with-label-link
  245. [format label link]
  246. (case format
  247. :org
  248. [(util/format "[[%s][%s]]" link label)
  249. (+ 4 (count link) (count label))]
  250. :markdown
  251. [(util/format "[%s](%s)" label link)
  252. (+ 4 (count link) (count label))]
  253. ["" 0]))
  254. (defn with-default-label
  255. [format label]
  256. (case format
  257. :org
  258. [(util/format "[[][%s]]" label)
  259. 2]
  260. :markdown
  261. [(util/format "[%s]()" label)
  262. (+ 3 (count label))]
  263. ["" 0]))
  264. (defn get-file-extension
  265. [format]
  266. (case (keyword format)
  267. :markdown
  268. "md"
  269. (name format)))
  270. (defonce default-journals-directory "journals")
  271. (defonce default-pages-directory "pages")
  272. (defonce default-whiteboards-directory "whiteboards")
  273. (defn get-pages-directory
  274. []
  275. (or (state/get-pages-directory) default-pages-directory))
  276. (defn get-journals-directory
  277. []
  278. (or (state/get-journals-directory) default-journals-directory))
  279. (defn get-whiteboards-directory
  280. []
  281. (or (state/get-whiteboards-directory) default-whiteboards-directory))
  282. (defonce demo-repo "Demo")
  283. (defn demo-graph?
  284. "Demo graph or nil graph?"
  285. ([]
  286. (demo-graph? (state/get-current-repo)))
  287. ([repo-url]
  288. (or (nil? repo-url) (= repo-url demo-repo)
  289. (string/ends-with? repo-url demo-repo))))
  290. (defonce recycle-dir ".recycle")
  291. (def config-file "config.edn")
  292. (def custom-css-file "custom.css")
  293. (def export-css-file "export.css")
  294. (def custom-js-file "custom.js")
  295. (def config-default-content (rc/inline "templates/config.edn"))
  296. (def config-default-content-md5 (let [md5 (new crypt/Md5)]
  297. (.update md5 (crypt/stringToUtf8ByteArray config-default-content))
  298. (crypt/byteArrayToHex (.digest md5))))
  299. ;; NOTE: repo-url is the unique identifier of a repo.
  300. ;; - `local` => in-memory demo graph
  301. ;; - `logseq_local_/absolute/path/to/graph` => local graph, native fs backend
  302. ;; - `logseq_local_x:/absolute/path/to/graph` => local graph, native fs backend, on Windows
  303. ;; - `logseq_local_GraphName` => local graph, browser fs backend
  304. ;; - `logseq_db_GraphName` => db based graph, sqlite as backend
  305. ;; - Use `""` while writing global files
  306. (defonce idb-db-prefix "logseq-db/")
  307. (defonce local-db-prefix "logseq_local_")
  308. (defonce local-handle "handle")
  309. (defonce db-version-prefix sqlite-util/db-version-prefix)
  310. (defn local-file-based-graph?
  311. [s]
  312. (and (string? s)
  313. (string/starts-with? s local-db-prefix)))
  314. (defn db-based-graph?
  315. ([]
  316. (db-based-graph? (state/get-current-repo)))
  317. ([s]
  318. (boolean
  319. (and (string? s)
  320. (sqlite-util/db-based-graph? s)))))
  321. (defn get-local-asset-absolute-path
  322. [s]
  323. (str "/" (string/replace s #"^[./]*" "")))
  324. (defn get-local-dir
  325. [repo]
  326. (if (db-based-graph? repo)
  327. (path/path-join (get-in @state/state [:system/info :home-dir])
  328. "logseq"
  329. "graphs"
  330. (string/replace repo db-version-prefix ""))
  331. (string/replace repo local-db-prefix "")))
  332. ;; FIXME(andelf): this is not the reverse op of get-repo-dir, should be fixed
  333. (defn get-local-repo
  334. [dir]
  335. (str local-db-prefix dir))
  336. (defn get-repo-dir
  337. [repo-url]
  338. (when repo-url
  339. (let [db-based? (db-based-graph? repo-url)]
  340. (cond
  341. (and (util/electron?) db-based-graph?)
  342. (get-local-dir repo-url)
  343. db-based?
  344. (str "memory:///"
  345. (string/replace-first repo-url db-version-prefix ""))
  346. (and (util/electron?) (local-file-based-graph? repo-url))
  347. (get-local-dir repo-url)
  348. (and (mobile-util/native-platform?) (local-file-based-graph? repo-url))
  349. (let [dir (get-local-dir repo-url)]
  350. (if (string/starts-with? dir "file://")
  351. dir
  352. (path/path-join "file://" dir)))
  353. ;; Special handling for demo graph
  354. (= repo-url demo-repo)
  355. "memory:///local"
  356. ;; nfs, browser-fs-access
  357. ;; Format: logseq_local_{dir-name}
  358. (local-file-based-graph? repo-url)
  359. (string/replace-first repo-url local-db-prefix "")
  360. ;; unit test
  361. (= repo-url "test-db")
  362. "/test-db"
  363. :else
  364. (do
  365. (js/console.error "Unknown Repo URL type:" repo-url)
  366. (str "/"
  367. (->> (take-last 2 (string/split repo-url #"/"))
  368. (string/join "_"))))))))
  369. (defn get-string-repo-dir
  370. [repo-dir]
  371. (if (mobile-util/native-ios?)
  372. (str (if (mobile-util/in-iCloud-container-path? repo-dir)
  373. "iCloud"
  374. (cond (mobile-util/native-iphone?)
  375. "On My iPhone"
  376. (mobile-util/native-ipad?)
  377. "On My iPad"
  378. :else
  379. "Local"))
  380. (->> (string/split repo-dir "Documents/")
  381. last
  382. common-util/safe-decode-uri-component
  383. (str "/" (string/capitalize app-name) "/")))
  384. (get-repo-dir (get-local-repo repo-dir))))
  385. (defn get-repo-fpath
  386. [repo-url path]
  387. (path/path-join (get-repo-dir repo-url) path))
  388. (defn get-repo-config-path
  389. []
  390. (path/path-join app-name config-file))
  391. (defn get-custom-css-path
  392. ([]
  393. (get-custom-css-path (state/get-current-repo)))
  394. ([repo]
  395. (if (db-based-graph? repo)
  396. (path/path-join app-name custom-css-file)
  397. (when-let [repo-dir (get-repo-dir repo)]
  398. (path/path-join repo-dir app-name custom-css-file)))))
  399. (defn get-export-css-path
  400. ([]
  401. (get-export-css-path (state/get-current-repo)))
  402. ([repo]
  403. (when-let [repo-dir (get-repo-dir repo)]
  404. (path/path-join repo-dir app-name export-css-file))))
  405. (defn expand-relative-assets-path
  406. "Resolve all relative links in custom.css to assets:// URL"
  407. ;; ../assets/xxx -> {assets|file}://{current-graph-root-path}/xxx
  408. [source]
  409. (when-not (string/blank? source)
  410. (let [protocol (and (string? source)
  411. (not (string/blank? source))
  412. (if (util/electron?) "assets://" "file://"))
  413. ;; BUG: use "assets" as fake current directory
  414. assets-link-fn (fn [_]
  415. (let [graph-root (get-repo-dir (state/get-current-repo))
  416. full-path (if (util/safe-re-find #"^(file|assets):" graph-root)
  417. (path/path-join graph-root "assets")
  418. (path/path-join protocol graph-root "assets"))]
  419. (str (cond-> full-path
  420. (mobile-util/native-platform?)
  421. (mobile-util/convert-file-src))
  422. "/")))]
  423. (string/replace source #"\.\./assets/" assets-link-fn))))
  424. (defn get-current-repo-assets-root
  425. []
  426. (when-let [repo-dir (get-repo-dir (state/get-current-repo))]
  427. (path/path-join repo-dir "assets")))
  428. (defn get-repo-assets-root
  429. [repo]
  430. (when-let [repo-dir (get-repo-dir repo)]
  431. (path/path-join repo-dir "assets")))
  432. (defn get-custom-js-path
  433. ([]
  434. (get-custom-js-path (state/get-current-repo)))
  435. ([repo]
  436. (if (db-based-graph? repo)
  437. (path/path-join app-name custom-js-file)
  438. (when-let [repo-dir (get-repo-dir repo)]
  439. (path/path-join repo-dir app-name custom-js-file)))))
  440. (defn get-block-hidden-properties
  441. []
  442. (:block-hidden-properties (state/get-config)))