Browse Source

Merge branch 'feat/db' of https://github.com/logseq/logseq into feat/db

Konstantinos Kaloutas 1 year ago
parent
commit
ca25e08532
65 changed files with 641 additions and 826 deletions
  1. 2 1
      deps/db/deps.edn
  2. 1 1
      deps/publishing/src/logseq/publishing/export.cljs
  3. 1 0
      deps/publishing/src/logseq/publishing/html.cljs
  4. 0 1
      deps/shui/src/logseq/shui/core.cljs
  5. 1 5
      deps/shui/src/logseq/shui/icon/v2.cljs
  6. 4 1
      docs/contributing-to-translations.md
  7. 1 2
      docs/dev-practices.md
  8. 0 3
      e2e-tests/basic.spec.ts
  9. 1 1
      public/index.html
  10. 1 1
      resources/index.html
  11. 13 13
      resources/package.json
  12. 44 31
      shadow-cljs.edn
  13. 2 1
      src/electron/electron/core.cljs
  14. 24 9
      src/electron/electron/git.cljs
  15. 7 0
      src/electron/electron/handler.cljs
  16. 8 14
      src/electron/electron/state.cljs
  17. 0 1
      src/main/frontend/commands.cljs
  18. 4 16
      src/main/frontend/common.css
  19. 92 77
      src/main/frontend/components/block.cljs
  20. 2 2
      src/main/frontend/components/export.cljs
  21. 1 8
      src/main/frontend/components/file.cljs
  22. 10 6
      src/main/frontend/components/query_table.cljs
  23. 26 11
      src/main/frontend/components/settings.cljs
  24. 8 2
      src/main/frontend/context/i18n.cljs
  25. 3 1
      src/main/frontend/db/model.cljs
  26. 45 12
      src/main/frontend/db_worker.cljs
  27. 6 9
      src/main/frontend/extensions/zip.cljs
  28. 3 3
      src/main/frontend/handler/db_based/status.cljs
  29. 15 14
      src/main/frontend/handler/editor.cljs
  30. 68 313
      src/main/frontend/handler/export.cljs
  31. 41 41
      src/main/frontend/handler/export/common.cljs
  32. 19 13
      src/main/frontend/handler/export/opml.cljs
  33. 17 13
      src/main/frontend/handler/export/text.cljs
  34. 0 1
      src/main/frontend/handler/property/util.cljs
  35. 2 1
      src/main/frontend/handler/repo.cljs
  36. 3 25
      src/main/frontend/handler/whiteboard.cljs
  37. 8 2
      src/main/frontend/handler/worker.cljs
  38. 2 2
      src/main/frontend/persist_db/browser.cljs
  39. 10 24
      src/main/frontend/publishing.cljs
  40. 2 2
      src/main/frontend/routes.cljs
  41. 12 10
      src/main/frontend/state.cljs
  42. 67 0
      src/main/frontend/worker/export.cljs
  43. 5 4
      src/main/frontend/worker/file/core.cljs
  44. 39 39
      src/main/logseq/api.cljs
  45. 0 1
      src/resources/dicts/de.edn
  46. 1 1
      src/resources/dicts/en.edn
  47. 1 1
      src/resources/dicts/es.edn
  48. 2 14
      src/resources/dicts/fr.edn
  49. 0 1
      src/resources/dicts/id.edn
  50. 0 1
      src/resources/dicts/it.edn
  51. 0 1
      src/resources/dicts/ja.edn
  52. 0 1
      src/resources/dicts/ko.edn
  53. 1 2
      src/resources/dicts/nb-no.edn
  54. 0 1
      src/resources/dicts/nl.edn
  55. 0 1
      src/resources/dicts/pl.edn
  56. 0 1
      src/resources/dicts/pt-br.edn
  57. 0 1
      src/resources/dicts/pt-pt.edn
  58. 0 1
      src/resources/dicts/ru.edn
  59. 0 1
      src/resources/dicts/sk.edn
  60. 0 1
      src/resources/dicts/tr.edn
  61. 0 1
      src/resources/dicts/uk.edn
  62. 0 1
      src/resources/dicts/zh-cn.edn
  63. 0 1
      src/resources/dicts/zh-hant.edn
  64. 10 51
      src/test/frontend/handler/export_test.cljs
  65. 6 6
      static/yarn.lock

+ 2 - 1
deps/db/deps.edn

@@ -3,7 +3,8 @@
  {datascript/datascript {:git/url "https://github.com/logseq/datascript" ;; fork
                          :sha     "21fc7880c7042fb1d9086135d162ea7a91681f89"}
   com.cognitect/transit-cljs   {:mvn/version "0.8.280"}
-  logseq/common                {:local/root "../common"}}
+  logseq/common                {:local/root "../common"}
+  funcool/promesa              {:mvn/version "4.0.2"}}
 
  :aliases
  {:clj-kondo

+ 1 - 1
deps/publishing/src/logseq/publishing/export.cljs

@@ -8,7 +8,7 @@
 
 (def ^:api js-files
   "js files from publishing release build"
-  ["main.js" "code-editor.js" "excalidraw.js" "tldraw.js"])
+  ["shared.js" "main.js" "code-editor.js" "excalidraw.js" "tldraw.js" "db-worker.js"])
 
 (def ^:api static-dirs
   "dirs under static dir to copy over"

+ 1 - 0
deps/publishing/src/logseq/publishing/html.cljs

@@ -122,6 +122,7 @@ necessary db filtering"
         }
       }(window.location))"]
             ;; TODO: should make this configurable
+            [:script {:src "static/js/shared.js"}]
             [:script {:src "static/js/main.js"}]
             [:script {:src "static/js/interact.min.js"}]
             [:script {:src "static/js/highlight.min.js"}]

+ 0 - 1
deps/shui/src/logseq/shui/core.cljs

@@ -17,7 +17,6 @@
 ;; icon
 (def icon shui.icon.v2/root)
 (def icon-v2 shui.icon.v2/root)
-(def tabler-icon shui.icon.v2/tabler-icon)
 
 ;; list-item
 (def list-item shui.list-item.v1/root)

+ 1 - 5
deps/shui/src/logseq/shui/icon/v2.cljs

@@ -14,13 +14,9 @@
 (def get-adapt-icon-class
   (memoize (fn [klass] (shui-utils/react->rum klass true))))
 
-(defn tabler-icon
-  [name]
-  (gobj/get js/tablerIcons (str "Icon" (csk/->PascalCase name))))
-
 (rum/defc root
   ([name] (root name nil))
-  ([name {:keys [extension? font? class size] :as opts}]
+  ([name {:keys [extension? font? class] :as opts}]
    (when-not (string/blank? name)
      (let [^js jsTablerIcons (gobj/get js/window "tablerIcons")]
        (if (or extension? font? (not jsTablerIcons))

+ 4 - 1
docs/contributing-to-translations.md

@@ -84,7 +84,10 @@ Almost all translations are small. The only exceptions to this are the keys `:tu
 
 * Some translations may include punctuation like `:` or `!`. When translating them, please use the punctuation that makes the most sense for your language as you don't have to follow the English ones.
 * Some translations may include arguments/interpolations e.g. `{1}`. If you see them in a translation, be sure to include them. These arguments are substituted in the string and are usually used for something the app needs to calculate e.g. a number. See [these docs](https://github.com/tonsky/tongue#interpolation) for more examples.
-* Rarely, a translation may need to translate formatted text by returning [hiccup-style HTML](https://github.com/weavejester/hiccup#syntax). In this case, a Clojure function is the recommended approach. For example, a function translation would look like `(fn [] [:div "FOO"])`. See `:on-boarding/main-title` for an example.
+* Rarely, a translation is a function that calls code and look like `(fn ... )`
+    * The logic for these fns must be simple and can only use the following fns: `str`, `when`, `if` and `=`.
+    * These fn translations are usually used to handle pluralization or handle formatted text by returning [hiccup-style HTML](https://github.com/weavejester/hiccup#syntax). For example, a hiccup style translation would look like `(fn [] [:div "FOO"])`. See `:on-boarding/main-title` for more examples.
+
 ## Fix Mistakes
 
 There is a lint command to catch common translation mistakes - `bb

+ 1 - 2
docs/dev-practices.md

@@ -90,8 +90,7 @@ translations here are some things to keep in mind:
   fn translation. Hiccup vectors are needed when word order matters for a
   translation and formatting is involved. See [this 3 word Turkish
   example](https://github.com/logseq/logseq/commit/1d932f07c4a0aad44606da6df03a432fe8421480#r118971415).
-* Translations can have arguments for interpolating strings. When they do, be
-  sure translators are using them correctly.
+* Translations can be anonymous fns with arguments for interpolating strings. Fns should be simple and only include the following fns: `str`, `when`, `if` and `=`.
 
 ### Spell Checker
 

+ 0 - 3
e2e-tests/basic.spec.ts

@@ -120,10 +120,7 @@ test('block selection', async ({ page, block }) => {
 
   await page.keyboard.press('ArrowDown')
   await block.waitForSelectedBlocks(2)
-  await page.keyboard.up('Shift')
-
   // mod+click select or deselect
-  await page.keyboard.down(modKey)
   await page.click('.ls-block >> nth=7')
   await block.waitForSelectedBlocks(1)
 

+ 1 - 1
public/index.html

@@ -52,10 +52,10 @@
 <script defer src="/static/js/interact.min.js"></script>
 <script defer src="/static/js/marked.min.js"></script>
 <script defer src="/static/js/html2canvas.min.js"></script>
-<script defer src="/static/js/shared.js"></script>
 <script defer src="/static/js/react.production.min.js"></script>
 <script defer src="/static/js/react-dom.production.min.js"></script>
 <script defer src="/static/js/ui.js"></script>
+<script defer src="/static/js/shared.js"></script>
 <script defer src="/static/js/main.js"></script>
 <script defer src="/static/js/amplify.js"></script>
 <script defer src="/static/js/tabler.min.js"></script>

+ 1 - 1
resources/index.html

@@ -52,10 +52,10 @@ const portal = new MagicPortal(worker);
 <script defer src="./js/marked.min.js"></script>
 <script defer src="./js/html2canvas.min.js"></script>
 <script defer src="./js/lsplugin.core.js"></script>
-<script defer src="./js/shared.js"></script>
 <script defer src="./js/react.production.min.js"></script>
 <script defer src="./js/react-dom.production.min.js"></script>
 <script defer src="./js/ui.js"></script>
+<script defer src="./js/shared.js"></script>
 <script defer src="./js/main.js"></script>
 <script defer src="./js/amplify.js"></script>
 <script defer src="./js/tabler.min.js"></script>

+ 13 - 13
resources/package.json

@@ -20,30 +20,30 @@
     "forge": "./forge.config.js"
   },
   "dependencies": {
+    "@fastify/cors": "8.2.0",
+    "@logseq/rsapi": "0.0.81",
+    "@sentry/electron": "2.5.1",
+    "abort-controller": "3.0.0",
+    "better-sqlite3": "9.3.0",
     "chokidar": "^3.5.1",
+    "command-exists": "1.2.9",
+    "diff-match-patch": "1.0.5",
     "dugite": "2.5.0",
+    "electron-deeplink": "1.0.10",
     "electron-dl": "3.3.0",
     "electron-log": "4.3.1",
     "electron-squirrel-startup": "1.0.0",
     "electron-window-state": "5.0.3",
+    "extract-zip": "2.0.1",
+    "fastify": "latest",
     "fs-extra": "9.1.0",
+    "https-proxy-agent": "7.0.2",
     "node-fetch": "2.6.7",
     "open": "7.3.1",
+    "posthog-js": "1.10.2",
     "semver": "7.5.2",
-    "update-electron-app": "2.0.1",
-    "extract-zip": "2.0.1",
-    "diff-match-patch": "1.0.5",
-    "https-proxy-agent": "7.0.2",
     "socks-proxy-agent": "8.0.2",
-    "@sentry/electron": "2.5.1",
-    "posthog-js": "1.10.2",
-    "@logseq/rsapi": "0.0.81",
-    "electron-deeplink": "1.0.10",
-    "abort-controller": "3.0.0",
-    "fastify": "latest",
-    "@fastify/cors": "8.2.0",
-    "command-exists": "1.2.9",
-    "better-sqlite3": "8.0.1"
+    "update-electron-app": "2.0.1"
   },
   "devDependencies": {
     "@electron-forge/cli": "^6.0.4",

+ 44 - 31
shadow-cljs.edn

@@ -8,13 +8,13 @@
  :js-options {:js-package-dirs ["node_modules" "tldraw/apps"]}
 
  :builds
- {:app {:target :browser
+ {:app {:target        :browser
         :module-loader true
-        :js-options {:ignore-asset-requires true
-             :resolve {"react" {:target :global
-                                :global "React"}
-                       "react-dom" {:target :global
-                                    :global "ReactDOM"}}} ;; handle `require(xxx.css)`
+        :js-options    {:ignore-asset-requires true
+                        :resolve {"react" {:target :global
+                                           :global "React"}
+                                  "react-dom" {:target :global
+                                               :global "ReactDOM"}}} ;; handle `require(xxx.css)`
         :modules       {:shared
                         {:entries []}
                         :main
@@ -97,36 +97,49 @@
 
   :publishing {:target :browser
                :module-loader true
-               :js-options {:ignore-asset-requires true}
-               :modules {:main
-                         {:init-fn frontend.publishing/init}
-                         :code-editor
-                         {:entries [frontend.extensions.code]
-                          :depends-on #{:main}}
-                         :excalidraw
-                         {:entries [frontend.extensions.excalidraw]
-                          :depends-on #{:main}}
-                         :tldraw
-                         {:entries [frontend.extensions.tldraw]
-                          :depends-on #{:main}}}
+               :js-options    {:ignore-asset-requires true
+                               :resolve {"react" {:target :global
+                                                  :global "React"}
+                                         "react-dom" {:target :global
+                                                      :global "ReactDOM"}}} ;; handle `require(xxx.css)`
+               :modules       {:shared
+                               {:entries []}
+                               :main
+                               {:init-fn    frontend.publishing/init
+                                :depends-on #{:shared}}
+                               :code-editor
+                               {:entries    [frontend.extensions.code]
+                                :depends-on #{:main}}
+                               :excalidraw
+                               {:entries    [frontend.extensions.excalidraw]
+                                :depends-on #{:main}}
+                               :tldraw
+                               {:entries    [frontend.extensions.tldraw]
+                                :depends-on #{:main}}
+                               :db-worker
+                               {:init-fn   frontend.db-worker/init
+                                :depends-on #{:shared}
+                                :web-worker true}}
 
-               :output-dir "./static/js/publishing"
-               :asset-path "static/js"
-               :closure-defines {frontend.config/PUBLISHING true
-                                 goog.debug.LOGGING_ENABLED true}
-               :compiler-options {:infer-externs :auto
+               :output-dir       "./static/js/publishing"
+               :asset-path       "static/js"
+               :closure-defines  {frontend.config/PUBLISHING true
+                                  goog.debug.LOGGING_ENABLED true}
+               :compiler-options {:infer-externs      :auto
                                   :output-feature-set :es-next
-                                  :externs ["datascript/externs.js"
-                                            "externs.js"]
-                                  :warnings {:fn-deprecated false
-                                             :redef false}}
-               :devtools {:before-load frontend.core/stop
-                          :after-load frontend.core/start
-                          :preloads [devtools.preload]}}
+                                  :externs            ["datascript/externs.js"
+                                                       "externs.js"]
+                                  :warnings           {:fn-deprecated false
+                                                       :redef false}
+                                  ;; https://github.com/thheller/shadow-cljs/issues/611#issuecomment-620845276
+                                  ;; fixes cljs.spec bug with code splitting
+                                  :cross-chunk-method-motion false}
+               :devtools         {:before-load frontend.core/stop
+                                  :after-load  frontend.core/start
+                                  :preloads    [devtools.preload]}}
 
   :stories-dev {:target :npm-module
                 :entries [logseq.shui.storybook]
                 :output-dir "packages/ui/.storybook/cljs"
                 :devtools {:enabled true}
                 :compiler-options {:optimizations :simple}}}}
-  

+ 2 - 1
src/electron/electron/core.cljs

@@ -256,7 +256,7 @@
 
            (db/ensure-graphs-dir!)
 
-           (git/auto-commit-current-graph!)
+           (git/configure-auto-commit!)
 
            (vreset! *setup-fn
                     (fn []
@@ -275,6 +275,7 @@
 
            ;; main window events
            (.on win "close" (fn [e]
+                                  (git/before-graph-close-hook!)
                                   (when @*quit-dirty? ;; when not updating
                                     (.preventDefault e)
 

+ 24 - 9
src/electron/electron/git.cljs

@@ -170,13 +170,28 @@
        (p/resolved result))
      (p/catch error-handler))))
 
-(defn auto-commit-current-graph!
+(defonce auto-commit-interval (atom nil))
+(defn- auto-commit-tick-fn
   []
-  (when (not (state/git-auto-commit-disabled?))
-    (state/clear-git-commit-interval!)
-    (js/setTimeout add-all-and-commit! 3000)
-    (let [seconds (state/get-git-commit-seconds)]
-      (when (int? seconds)
-        (js/setTimeout add-all-and-commit! 5000)
-        (let [interval (js/setInterval add-all-and-commit! (* seconds 1000))]
-          (state/set-git-commit-interval! interval))))))
+  (when (state/git-auto-commit-enabled?)
+    (add-all-and-commit!)))
+
+(defn configure-auto-commit!
+  "Configure auto commit interval, reentrantable"
+  []
+  (when @auto-commit-interval
+    (swap! auto-commit-interval js/clearInterval))
+  (when (state/git-auto-commit-enabled?)
+    (let [seconds (state/get-git-commit-seconds)
+          millis (if (int? seconds)
+                   (* seconds 1000)
+                   6000)]
+      (logger/info ::set-auto-commit-interval seconds)
+      (js/setTimeout add-all-and-commit! 100)
+      (reset! auto-commit-interval (js/setInterval auto-commit-tick-fn millis)))))
+
+(defn before-graph-close-hook!
+  []
+  (when (and (state/git-auto-commit-enabled?)
+             (state/git-commit-on-close-enabled?))
+    (add-all-and-commit!)))

+ 7 - 0
src/electron/electron/handler.cljs

@@ -31,6 +31,7 @@
             [electron.handler-interface :refer [handle]]
             [logseq.db.sqlite.util :as sqlite-util]
             [logseq.db.sqlite.db :as sqlite-db]
+            [goog.functions :refer [debounce]]
             [logseq.common.graph :as common-graph]
             [promesa.core :as p]
             [clojure.edn :as edn]))
@@ -474,6 +475,12 @@
 (defmethod handle :gitStatus [_ [_]]
   (git/short-status!))
 
+(def debounced-configure-auto-commit! (debounce git/configure-auto-commit! 5000))
+(defmethod handle :setGitAutoCommit []
+  (debounced-configure-auto-commit!)
+  nil)
+
+
 (defmethod handle :installMarketPlugin [_ [_ mft]]
   (plugin/install-or-update! mft))
 

+ 8 - 14
src/electron/electron/state.cljs

@@ -3,9 +3,7 @@
             [medley.core :as medley]))
 
 (defonce state
-  (atom {:git/auto-commit-interval nil
-
-         :config (config/get-config)
+  (atom {:config (config/get-config)
 
          ;; FIXME: replace with :window/graph
          :graph/current nil
@@ -22,22 +20,18 @@
     (swap! state assoc-in path value)
     (swap! state assoc path value)))
 
-(defn set-git-commit-interval!
-  [v]
-  (set-state! :git/auto-commit-interval v))
-
-(defn clear-git-commit-interval!
-  []
-  (when-let [interval (get @state :git/auto-commit-interval)]
-    (js/clearInterval interval)))
-
 (defn get-git-commit-seconds
   []
   (get-in @state [:config :git/auto-commit-seconds] 60))
 
-(defn git-auto-commit-disabled?
+(defn git-auto-commit-enabled?
+  []
+  ;; For backward compatibility, use negative logic
+  (false? (get-in @state [:config :git/disable-auto-commit?] true)))
+
+(defn git-commit-on-close-enabled?
   []
-  (get-in @state [:config :git/disable-auto-commit?] true))
+  (get-in @state [:config :git/commit-on-close?] false))
 
 (defn get-graph-path
   []

+ 0 - 1
src/main/frontend/commands.cljs

@@ -26,7 +26,6 @@
             [logseq.common.util.page-ref :as page-ref]
             [promesa.core :as p]
             [frontend.handler.file-based.status :as file-based-status]
-            [frontend.handler.db-based.status :as db-based-status]
             [frontend.handler.db-based.property :as db-property-handler]))
 
 ;; TODO: move to frontend.handler.editor.commands

+ 4 - 16
src/main/frontend/common.css

@@ -61,7 +61,7 @@ html[data-theme='dark'] {
   --ls-link-text-hover-color: var(--ls-active-secondary-color);
   --ls-link-ref-text-color: var(--ls-link-text-color);
   --ls-link-ref-text-hover-color: var(--ls-link-text-hover-color);
-  --ls-tag-text-color: var(--ls-secondary-text-color);
+  --ls-tag-text-color: var(--ls-link-text-color);
   --ls-tag-text-hover-color: var(--ls-link-text-hover-color);
   --ls-slide-background-color: var(--ls-primary-background-color);
   --ls-block-bullet-border-color: #0f4958;
@@ -142,7 +142,7 @@ html[data-theme='light'] {
   --ls-link-text-hover-color: #1a537c;
   --ls-link-ref-text-color: var(--ls-link-text-color);
   --ls-link-ref-text-hover-color: var(--ls-link-text-hover-color);
-  --ls-tag-text-color: var(--ls-secondary-text-color);
+  --ls-tag-text-color: var(--ls-link-ref-text-color);
   --ls-tag-text-hover-color: var(--ls-link-ref-text-hover-color);
   --ls-slide-background-color: #fff;
   --ls-block-bullet-border-color: #dedede;
@@ -526,15 +526,12 @@ i.ti {
 
 /* region FIXME: override elements (?) */
 h1.title, h1.title input {
+  margin-bottom: 1.5rem;
   color: or(--ls-journal-title-color, --lx-gray-12, --ls-title-text-color, #222);
   font-size: var(--ls-page-title-size, 36px);
   font-weight: 500;
 }
 
-h1.title {
-  margin-bottom: 1.5rem;
-}
-
 .title .page-icon {
   margin-right: 12px;
 }
@@ -682,6 +679,7 @@ img.small {
 }
 
 a.tag {
+  font-size: 0.9em;
   text-align: center;
   text-decoration: none;
   display: inline-block;
@@ -935,13 +933,3 @@ html.is-mobile {
     @apply inline-block;
   }
 }
-
-h1.title {
-    @apply text-2xl;
-}
-h2.title {
-    @apply text-xl;
-}
-h3.title {
-    @apply text-lg;
-}

+ 92 - 77
src/main/frontend/components/block.cljs

@@ -547,7 +547,6 @@
    All page-names are sanitized except page-name-in-block"
   [state config page-name-in-block page-name redirect-page-name page-entity contents-page? children html-export? label whiteboard-page?]
   (let [*hover? (::hover? state)
-        ;; FIXME: Bring back fix from https://github.com/logseq/logseq/pull/10434/commits/42f68ce32e7a035e6926bc2798d46843bbd70297
         *mouse-down? (::mouse-down? state)
         tag? (:tag? config)
         breadcrumb? (:breadcrumb? config)
@@ -1783,7 +1782,7 @@
          :on-click (fn [event]
                      (util/stop event)
                      (state/clear-edit!)
-                     (if (or ref? config/publishing?)
+                     (if ref?
                        (state/toggle-collapsed-block! uuid)
                        (if collapsed?
                          (editor-handler/expand-block! uuid)
@@ -2177,65 +2176,75 @@
 
 (defn- block-content-on-mouse-down
   [e block block-id content edit-input-id ref]
-  (let [repo (state/get-current-repo)]
-    (when-not (> (count content) (state/block-content-max-length repo))
-      (let [target (gobj/get e "target")
-            button (gobj/get e "buttons")
-            shift? (gobj/get e "shiftKey")
-            meta? (util/meta-key? e)
-            forbidden-edit? (target-forbidden-edit? target)]
-        (if (and meta?
-                 (not (state/get-edit-input-id))
-                 (not (dom/has-class? target "page-ref"))
-                 (not= "A" (gobj/get target "tagName")))
-          (do
-            (util/stop e)
-            (state/conj-selection-block! (gdom/getElement block-id) :down)
-            (when block-id
-              (state/set-selection-start-block! block-id)))
-          (when (contains? #{1 0} button)
-            (when-not forbidden-edit?
-              (cond
-                (and shift? (state/get-selection-start-block-or-first))
-                (do
-                  (util/stop e)
-                  (util/clear-selection!)
-                  (editor-handler/highlight-selection-area! block-id))
-
-                shift?
-                (util/clear-selection!)
+  (when-not (> (count content) (state/block-content-max-length (state/get-current-repo)))
+    (let [target (gobj/get e "target")
+          button (gobj/get e "buttons")
+          shift? (gobj/get e "shiftKey")
+          meta? (util/meta-key? e)
+          forbidden-edit? (target-forbidden-edit? target)]
+      (when (and (not forbidden-edit?) (contains? #{1 0} button))
+        (util/stop-propagation e)
+        (let [selection-blocks (state/get-selection-blocks)
+              starting-block (state/get-selection-start-block-or-first)]
+          (cond
+            (and meta? shift?)
+            (when-not (empty? selection-blocks)
+              (util/stop e)
+              (editor-handler/highlight-selection-area! block-id true))
+
+            meta?
+            (do
+              (util/stop e)
+              (let [block-dom-element (gdom/getElement block-id)]
+                (if (some #(= block-dom-element %) selection-blocks)
+                  (state/drop-selection-block! block-dom-element)
+                  (state/conj-selection-block! block-dom-element :down)))
+              (if (empty? (state/get-selection-blocks))
+                (state/clear-selection!)
+                (state/set-selection-start-block! block-id)))
+
+            (and shift? starting-block)
+            (do
+              (util/stop e)
+              (util/clear-selection!)
+              (editor-handler/highlight-selection-area! block-id))
+
+            shift?
+            (do
+              (util/clear-selection!)
+              (state/set-selection-start-block! block-id))
 
-                :else
-                (do
-                  (editor-handler/clear-selection!)
-                  (editor-handler/unhighlight-blocks!)
-                  (let [f #(let [block (or (db/entity [:block/uuid (:block/uuid block)]) block)
-                                 cursor-range (some-> (gdom/getElement block-id)
-                                                      (dom/by-class "block-content-wrapper")
-                                                      first
-                                                      util/caret-range)
-                                 {:block/keys [content format]} block
-                                 content (if (config/db-based-graph? repo)
-                                           (or (:block/original-name block) content)
-                                           (->> content
-                                                (property-file/remove-built-in-properties-when-file-based
-                                                 (state/get-current-repo) format)
-                                                (drawer/remove-logbook)))]
-                             (state/set-editing!
-                              edit-input-id
-                              content
-                              block
-                              cursor-range
-                              {:ref ref
-                               :move-cursor? false}))]
-                   ;; wait a while for the value of the caret range
-                    (p/do!
-                     (state/pub-event! [:editor/save-code-editor])
-                     (if (util/ios?)
-                       (f)
-                       (js/setTimeout f 5)))
-
-                    (when block-id (state/set-selection-start-block! block-id))))))))))))
+            :else
+            (do
+              (editor-handler/clear-selection!)
+              (editor-handler/unhighlight-blocks!)
+              (let [f #(let [block (or (db/entity [:block/uuid (:block/uuid block)]) block)
+                             cursor-range (some-> (gdom/getElement block-id)
+                                                  (dom/by-class "block-content-wrapper")
+                                                  first
+                                                  util/caret-range)
+                             {:block/keys [content format]} block
+                             content (if (config/db-based-graph? (state/get-current-repo))
+                                       (or (:block/original-name block) content)
+                                       (->> content
+                                            (property-file/remove-built-in-properties-when-file-based
+                                             (state/get-current-repo) format)
+                                            (drawer/remove-logbook)))]
+                         (state/set-editing!
+                          edit-input-id
+                          content
+                          block
+                          cursor-range
+                          {:ref ref
+                           :move-cursor? false}))]
+                ;; wait a while for the value of the caret range
+                (p/do!
+                 (state/pub-event! [:editor/save-code-editor])
+                 (if (util/ios?)
+                   (f)
+                   (js/setTimeout f 5)))
+
+                (state/set-selection-start-block! block-id)))))))))
 
 (rum/defc dnd-separator-wrapper < rum/reactive
   [block children block-id slide? top? block-content?]
@@ -2946,7 +2955,7 @@
         *control-show? (get container-state ::control-show?)
         db-collapsed? (util/collapsed? block)
         collapsed? (cond
-                     (or config/publishing? ref-or-custom-query? (root-block? config block))
+                     (or ref-or-custom-query? (root-block? config block))
                      (state/sub-collapsed uuid)
 
                      :else
@@ -3016,26 +3025,32 @@
        (when top?
          (dnd-separator-wrapper block children block-id slide? true false))
 
-     [:div.block-main-container.flex.flex-row.pr-2
-      {:class (if (and heading? (seq (:block/title block))) "items-baseline" "")
-       :on-touch-start (fn [event uuid] (block-handler/on-touch-start event uuid))
-       :on-touch-move (fn [event]
-                        (block-handler/on-touch-move event block uuid edit? *show-left-menu? *show-right-menu?))
-       :on-touch-end (fn [event]
-                       (block-handler/on-touch-end event block uuid *show-left-menu? *show-right-menu?))
-       :on-touch-cancel (fn [_e]
-                          (block-handler/on-touch-cancel *show-left-menu? *show-right-menu?))
-       :on-mouse-over (fn [e]
-                        (block-mouse-over e *control-show? block-id doc-mode?))
-       :on-mouse-leave (fn [e]
-                         (block-mouse-leave e *control-show? block-id doc-mode?))}
-      (when (not slide?)
-        (block-control config block uuid block-id collapsed? *control-show? edit? selected?))
+       [:div.block-main-container.flex.flex-row.pr-2
+        {:class (if (and heading? (seq (:block/title block))) "items-baseline" "")
+         :on-touch-start (fn [event uuid] (block-handler/on-touch-start event uuid))
+         :on-touch-move (fn [event]
+                          (block-handler/on-touch-move event block uuid edit? *show-left-menu? *show-right-menu?))
+         :on-touch-end (fn [event]
+                         (block-handler/on-touch-end event block uuid *show-left-menu? *show-right-menu?))
+         :on-touch-cancel (fn [_e]
+                            (block-handler/on-touch-cancel *show-left-menu? *show-right-menu?))
+         :on-mouse-over (fn [e]
+                          (block-mouse-over e *control-show? block-id doc-mode?))
+         :on-mouse-leave (fn [e]
+                           (block-mouse-leave e *control-show? block-id doc-mode?))}
+        (when (and (not slide?) (not in-whiteboard?) (not hidden?))
+          (let [edit? (or edit?
+                             (= uuid (:block/uuid (state/get-edit-block)))
+                             (contains? @(:editor/new-created-blocks @state/state) uuid))]
+            (block-control config block uuid block-id collapsed? *control-show? edit? selected?)))
+
+        (when (and @*show-left-menu? (not in-whiteboard?) (not hidden?))
+          (block-left-menu config block))
 
         (when-not hidden?
           (if whiteboard-block?
             (block-reference {} (str uuid) nil)
-        ;; Not embed self
+            ;; Not embed self
             [:div.flex.flex-col.w-full
              (let [block (merge block (block/parse-title-and-body uuid (:block/format block) pre-block? content))
                    hide-block-refs-count? (and (:embed? config)

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

@@ -22,10 +22,10 @@
      [:h1.title (t :export)]
      [:ul.mr-1
       [:li.mb-4
-       [:a.font-medium {:on-click #(export/export-repo-as-edn-v2! current-repo)}
+       [:a.font-medium {:on-click #(export/export-repo-as-edn! current-repo)}
         (t :export-edn)]]
       [:li.mb-4
-       [:a.font-medium {:on-click #(export/export-repo-as-json-v2! current-repo)}
+       [:a.font-medium {:on-click #(export/export-repo-as-json! current-repo)}
         (t :export-json)]]
       (when (config/db-based-graph? current-repo)
        [:li.mb-4

+ 1 - 8
src/main/frontend/components/file.cljs

@@ -10,7 +10,6 @@
             [frontend.date :as date]
             [frontend.db :as db]
             [frontend.fs :as fs]
-            [frontend.handler.export :as export-handler]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.util :as util]
@@ -57,13 +56,7 @@
                      (if (or (nil? modified-at) (zero? modified-at))
                        (t :file/no-data)
                        (date/get-date-time-string
-                        (t/to-default-time-zone (tc/to-date-time modified-at))))]])
-
-             (when-not mobile?
-               [:td [:a.text-sm
-                     {:on-click (fn [_e]
-                                  (export-handler/download-file! file))}
-                     [:span (t :download)]]])]))]])))
+                        (t/to-default-time-zone (tc/to-date-time modified-at))))]])]))]])))
 
 (rum/defc files
   []

+ 10 - 6
src/main/frontend/components/query_table.cljs

@@ -179,9 +179,10 @@
                (get-in row [:block/content]))
     :block (or (get-in row [:block/original-name])
                (get-in row [:block/content]))
-    (or (get-in row [:block/properties column])
-        (get-in row [:block/properties-text-values column])
-        (get-in row [(keyword :block column)]))))
+
+           (or (get-in row [:block/properties column])
+               (get-in row [:block/properties-text-values column])
+               (get-in row [(keyword :block column)]))))
 
 (defn- render-column-value
   [{:keys [row-block row-format cell-format value]} page-cp inline-text {:keys [uuid-names db-graph?]}]
@@ -204,7 +205,7 @@
     ;; inline-text when no page entity is found
     (string? value) (if-let [page (db/entity [:block/name (util/page-name-sanity-lc value)])]
                       (page-cp {} page)
-                       (inline-text row-block row-format value))
+                      (inline-text row-block row-format value))
     ;; render uuids as page refs
     (uuid? value)
     (page-cp {} {:block/name (get uuid-names value)})
@@ -251,7 +252,7 @@
             (sortable-title title column sort-state (:block/uuid current-block))))]]
       [:tbody
        (for [row sort-result]
-         (let [row-format (:block/format row)]
+         (let [format (:block/format row)]
            [:tr.cursor
             (for [column columns]
               (let [[cell-format value] (build-column-value row
@@ -273,7 +274,10 @@
                                                           :block-ref)
                                                          (reset! *mouse-down? false)))}
                  (when value
-                   (render-column-value {:row-block row :row-format row-format :cell-format cell-format :value value}
+                   (render-column-value {:row-block row
+                                         :row-format format
+                                         :cell-format cell-format
+                                         :value value}
                                         page-cp
                                         inline-text
                                         {:uuid-names uuid-names

+ 26 - 11
src/main/frontend/components/settings.cljs

@@ -249,7 +249,24 @@
          enabled?
          (fn []
            (state/set-state! [:electron/user-cfgs :git/disable-auto-commit?] enabled?)
-           (ipc/ipc :userAppCfgs :git/disable-auto-commit? enabled?))
+           (p/do!
+            (ipc/ipc :userAppCfgs :git/disable-auto-commit? enabled?)
+            (ipc/ipc :setGitAutoCommit)))
+         true)]]]))
+
+(rum/defcs switch-git-commit-on-close-row < rum/reactive
+  [state t]
+  (let [enabled? (state/get-git-commit-on-close-enabled?)]
+    [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center
+     [:label.block.text-sm.font-medium.leading-5.opacity-70
+      (t :settings-page/git-commit-on-close)]
+     [:div
+      [:div.rounded-md.sm:max-w-xs
+       (ui/toggle
+         enabled?
+         (fn []
+           (state/set-state! [:electron/user-cfgs :git/commit-on-close?] (not enabled?))
+           (ipc/ipc :userAppCfgs :git/commit-on-close? (not enabled?)))
          true)]]]))
 
 (rum/defcs git-auto-commit-seconds < rum/reactive
@@ -266,13 +283,14 @@
                           (let [value (-> (util/evalue event)
                                           util/safe-parse-int)]
                             (if (and (number? value)
-                                     (< 0 value (inc 600)))
-                              (do
+                                     (< 0 value (inc 86400)))
+                              (p/do!
                                 (state/set-state! [:electron/user-cfgs :git/auto-commit-seconds] value)
-                                (ipc/ipc :userAppCfgs :git/auto-commit-seconds value))
+                                (ipc/ipc :userAppCfgs :git/auto-commit-seconds value)
+                                (ipc/ipc :setGitAutoCommit))
                               (when-let [elem (gobj/get event "target")]
                                 (notification/show!
-                                 [:div "Invalid value! Must be a number between 1 and 600."]
+                                 [:div "Invalid value! Must be a number between 1 and 86400"]
                                  :warning true)
                                 (gobj/set elem "value" secs)))))}]]]]))
 
@@ -720,7 +738,7 @@
      [:p (t :settings-page/git-tip)])
     [:span.text-sm.opacity-50.my-4
      (t :settings-page/git-desc-1)]
-    [:br][:br]
+    [:br] [:br]
     [:span.text-sm.opacity-50.my-4
      (t :settings-page/git-desc-2)]
     [:a {:href "https://git-scm.com/" :target "_blank"}
@@ -729,11 +747,8 @@
      (t :settings-page/git-desc-3)]]
    [:br]
    (switch-git-auto-commit-row t)
-   (git-auto-commit-seconds t)
-
-   (ui/admonition
-     :warning
-     [:p (t :settings-page/git-confirm)])])
+   (switch-git-commit-on-close-row t)
+   (git-auto-commit-seconds t)])
 
 (rum/defc settings-advanced < rum/reactive
   []

+ 8 - 2
src/main/frontend/context/i18n.cljs

@@ -4,7 +4,8 @@
   throughout the application."
   (:require [frontend.dicts :as dicts]
             [tongue.core :as tongue]
-            [frontend.state :as state]))
+            [frontend.state :as state]
+            [lambdaisland.glogi :as log]))
 
 (def dicts (merge dicts/dicts {:tongue/fallback :en}))
 
@@ -17,7 +18,12 @@
     (try
       (apply translate preferred-language args)
       (catch :default e
-        (js/console.error "Translating dict" e)
+        (log/error :failed-translation {:arguments args
+                                        :lang preferred-language})
+        (state/pub-event! [:capture-error {:error e
+                                           :payload {:type :failed-translation
+                                                     :arguments args
+                                                     :lang preferred-language}}])
         (apply translate :en args)))))
 
 (defn- fetch-local-language []

+ 3 - 1
src/main/frontend/db/model.cljs

@@ -620,7 +620,9 @@ independent of format as format specific heading characters are stripped"
          page-name'
 
          (nil? page-entity)
-         page-name
+         (if-let [journal-name (date/journal-title->custom-format page-name)]
+           (util/page-name-sanity-lc journal-name)
+           page-name)
 
          (page-empty-or-dummy? (state/get-current-repo) (:db/id page-entity))
          (let [source-page (get-alias-source-page (state/get-current-repo) page-name')]

+ 45 - 12
src/main/frontend/db_worker.cljs

@@ -15,6 +15,7 @@
             [logseq.db.sqlite.util :as sqlite-util]
             [frontend.worker.state :as worker-state]
             [frontend.worker.file :as file]
+            [frontend.worker.export :as worker-export]
             [logseq.db :as ldb]
             [frontend.worker.rtc.op-mem-layer :as op-mem-layer]
             [frontend.worker.rtc.db-listener :as rtc-db-listener]
@@ -29,6 +30,7 @@
 (defonce *sqlite-conns worker-state/*sqlite-conns)
 (defonce *datascript-conns worker-state/*datascript-conns)
 (defonce *opfs-pools worker-state/*opfs-pools)
+(defonce *publishing? (atom false))
 
 (defn- get-pool-name
   [graph-name]
@@ -36,16 +38,21 @@
 
 (defn- <get-opfs-pool
   [graph]
-  (or (worker-state/get-opfs-pool graph)
-      (p/let [^js pool (.installOpfsSAHPoolVfs @*sqlite #js {:name (get-pool-name graph)
-                                                             :initialCapacity 20})]
-        (swap! *opfs-pools assoc graph pool)
-        pool)))
+  (when-not @*publishing?
+    (or (worker-state/get-opfs-pool graph)
+        (p/let [^js pool (.installOpfsSAHPoolVfs @*sqlite #js {:name (get-pool-name graph)
+                                                               :initialCapacity 20})]
+          (swap! *opfs-pools assoc graph pool)
+          pool))))
 
 (defn- init-sqlite-module!
   []
   (when-not @*sqlite
-    (p/let [electron? (string/includes? (.. js/location -href) "electron=true")
+    (p/let [href (.. js/location -href)
+            electron? (string/includes? href "electron=true")
+            publishing? (string/includes? href "publishing=true")
+
+            _ (reset! *publishing? publishing?)
             base-url (str js/self.location.protocol "//" js/self.location.host)
             sqlite-wasm-url (if electron?
                               (js/URL. "sqlite3.wasm" (.. js/location -href))
@@ -103,9 +110,7 @@
                     #js {:$addr addr
                          :$content (pr-str data)})
                   addr+data-seq)]
-        ;; async write so that UI can be refreshed earlier
-        (async/go
-          (upsert-addr-content! repo data delete-addrs))))
+        (upsert-addr-content! repo data delete-addrs)))
 
     (-restore [_ addr]
       (restore-data-from-addr repo addr))))
@@ -131,15 +136,25 @@
   (let [{:keys [db search]} (@*sqlite-conns repo)]
     (close-db-aux! repo db search)))
 
-(defn- create-or-open-db!
+(defn- get-db-and-search-db
   [repo]
-  (when-not (worker-state/get-sqlite-conn repo)
+  (if @*publishing?
+    (p/let [^object DB (.-DB ^object (.-oo1 ^object @*sqlite))
+            db (new DB "/db.sqlite" "ct")
+            search-db (new DB "/search-db.sqlite" "ct")]
+      [db search-db])
     (p/let [^js pool (<get-opfs-pool repo)
             capacity (.getCapacity pool)
             _ (when (zero? capacity)   ; file handle already releases since pool will be initialized only once
                 (.acquireAccessHandles pool))
             db (new (.-OpfsSAHPoolDb pool) repo-path)
-            search-db (new (.-OpfsSAHPoolDb pool) (str "search" repo-path))
+            search-db (new (.-OpfsSAHPoolDb pool) (str "search" repo-path))]
+      [db search-db])))
+
+(defn- create-or-open-db!
+  [repo]
+  (when-not (worker-state/get-sqlite-conn repo)
+    (p/let [[db search-db] (get-db-and-search-db repo)
             storage (new-sqlite-storage repo {})]
       (swap! *sqlite-conns assoc repo {:db db
                                        :search search-db})
@@ -390,6 +405,24 @@
      (worker-state/set-new-state! new-state)
      nil))
 
+  ;; Export
+  (block->content
+   [this repo block-uuid-or-page-name tree->file-opts context]
+   (when-let [conn (worker-state/get-datascript-conn repo)]
+     (worker-export/block->content repo @conn block-uuid-or-page-name
+                                   (edn/read-string tree->file-opts)
+                                   (edn/read-string context))))
+
+  (get-all-pages
+   [this repo]
+   (when-let [conn (worker-state/get-datascript-conn repo)]
+     (pr-str (worker-export/get-all-pages repo @conn))))
+
+  (get-all-page->content
+   [this repo]
+   (when-let [conn (worker-state/get-datascript-conn repo)]
+     (pr-str (worker-export/get-all-page->content repo @conn))))
+
   ;; RTC
   (rtc-start
    [this repo token]

+ 6 - 9
src/main/frontend/extensions/zip.cljs

@@ -1,6 +1,5 @@
 (ns frontend.extensions.zip
   (:require [clojure.string :as string]
-            [frontend.config :as config]
             ["jszip" :as JSZip]
             [promesa.core :as p]))
 
@@ -11,15 +10,13 @@
     (aset args "lastModified" last-modified)
     (js/File. blob-content file-name args)))
 
-(defn make-zip [zip-filename file-name->content repo]
+(defn make-zip [zip-filename file-name->content _repo]
   (let [zip (JSZip.)
-        zip-foldername (subs zip-filename (inc (string/last-index-of zip-filename "/")))
-        src-filepath (string/replace repo config/local-db-prefix "")
-        folder (.folder zip zip-foldername)]
+        folder (.folder zip zip-filename)]
     (doseq [[file-name content] file-name->content]
-      (.file folder (-> file-name
-                        (string/replace src-filepath "")
-                        (string/replace #"^/+" ""))
-             content))
+      (when-not (string/blank? content)
+        (.file folder (-> file-name
+                          (string/replace #"^/+" ""))
+               content)))
     (p/let [zip-blob (.generateAsync zip #js {:type "blob"})]
       (make-file zip-blob (str zip-filename ".zip") {:type "application/zip"}))))

+ 3 - 3
src/main/frontend/handler/db_based/status.cljs

@@ -15,6 +15,6 @@
                                                status-id
                                                {}))))
 
-(defn cycle-status!
-  [block status]
-  )
+(comment
+  (defn cycle-status!
+   [block status]))

+ 15 - 14
src/main/frontend/handler/editor.cljs

@@ -346,14 +346,14 @@
                    (not has-children?))]
     (p/do!
      (save-current-block! {:current-block current-block})
-
      (ui-outliner-tx/transact!
       {:outliner-op :insert-blocks}
        (outliner-core/insert-blocks! (state/get-current-repo) (db/get-db false)
                                     [new-block] current-block {:sibling? sibling?
                                                                :keep-uuid? keep-uuid?
-                                                               :replace-empty-target? replace-empty-target?
-                                                               :ordered-list? ordered-list?})))))
+                                                               :ordered-list? ordered-list?
+                                                               :replace-empty-target? replace-empty-target?})))))
+
 
 (defn- block-self-alone-when-insert?
   [config uuid]
@@ -479,8 +479,7 @@
 
 (defn api-insert-new-block!
   [content {:keys [page block-uuid sibling? before? properties
-                   custom-uuid replace-empty-target? edit-block? ordered-list?
-                   other-attrs]
+                   custom-uuid replace-empty-target? edit-block? ordered-list? other-attrs]
             :or {sibling? false
                  before? false
                  edit-block? true}}]
@@ -549,11 +548,10 @@
                                    nil)]
           (when block-m
             (p/do!
-             (outliner-insert-block! {} block-m new-block
-                                     {:sibling?              sibling?
-                                      :keep-uuid?            true
-                                      :replace-empty-target? replace-empty-target?
-                                      :ordered-list? ordered-list?})
+             (outliner-insert-block! {} block-m new-block {:sibling? sibling?
+                                                           :keep-uuid? true
+                                                           :ordered-list? ordered-list?
+                                                           :replace-empty-target? replace-empty-target?})
              (when edit-block?
               (if (and replace-empty-target?
                        (string/blank? (:block/content last-block)))
@@ -1200,9 +1198,8 @@
        (if append?
          (do (state/clear-edit!)
              (state/conj-selection-block! blocks direction))
-         (if (state/get-edit-input-id)
-           (state/exit-editing-and-set-selected-blocks! blocks direction)
-           (state/set-selection-blocks! blocks direction)))))))
+         (state/exit-editing-and-set-selected-blocks! blocks direction))))))
+
 
 (defn- select-block-up-down
   [direction]
@@ -2873,7 +2870,11 @@
                                               (block-handler/get-top-level-blocks [block])
                                               indent?
                                               {:get-first-block-original block-handler/get-first-block-original
-                                               :logical-outdenting? (state/logical-outdenting?)}))))))
+                                               :logical-outdenting? (state/logical-outdenting?)})
+         (edit-block!
+           (db/pull (:db/id block))
+           (cursor/pos (state/get-input))
+           (:block/uuid block)))))))
 
 (defn keydown-tab-handler
   [direction]

+ 68 - 313
src/main/frontend/handler/export.cljs

@@ -5,74 +5,24 @@
    [clojure.set :as s]
    [clojure.string :as string]
    [clojure.walk :as walk]
-   [datascript.core :as d]
    [frontend.config :as config]
    [frontend.db :as db]
    [frontend.extensions.zip :as zip]
    [frontend.external.roam-export :as roam-export]
-   [frontend.format.mldoc :as mldoc]
    [frontend.handler.notification :as notification]
    [frontend.mobile.util :as mobile-util]
-   [frontend.modules.file.core :as outliner-file]
-   [frontend.modules.outliner.tree :as outliner-tree]
    [logseq.publishing.html :as publish-html]
    [frontend.state :as state]
    [frontend.util :as util]
-   [frontend.handler.property.file :as property-file]
    [goog.dom :as gdom]
    [lambdaisland.glogi :as log]
-   [logseq.graph-parser.property :as gp-property]
-   [logseq.common.util.block-ref :as block-ref]
-   [logseq.common.util.page-ref :as page-ref]
    [promesa.core :as p]
-   [frontend.persist-db :as persist-db])
+   [frontend.persist-db :as persist-db]
+   [cljs-bean.core :as bean]
+   [frontend.handler.export.common :as export-common-handler])
   (:import
    [goog.string StringBuffer]))
 
-(defn- get-page-content
-  [repo page]
-  (outliner-file/tree->file-content
-   (outliner-tree/blocks->vec-tree
-    (db/get-page-blocks-no-cache repo page) page) {:init-level 1}))
-
-(defn- get-file-content
-  [repo file-path]
-  (if-let [page-name
-           (ffirst (d/q '[:find ?pn
-                          :in $ ?path
-                          :where
-                          [?p :block/file ?f]
-                          [?p :block/name ?pn]
-                          [?f :file/path ?path]]
-                        (db/get-db repo) file-path))]
-    (get-page-content repo page-name)
-    (ffirst
-     (d/q '[:find ?content
-            :in $ ?path
-            :where
-            [?f :file/path ?path]
-            [?f :file/content ?content]]
-          (db/get-db repo) file-path))))
-
-(defn- get-blocks-contents
-  [repo root-block-uuid]
-  (->
-   (db/get-block-and-children repo root-block-uuid)
-   (outliner-tree/blocks->vec-tree (str root-block-uuid))
-   (outliner-file/tree->file-content {:init-level 1})))
-
-(defn download-file!
-  [file-path]
-  (when-let [repo (state/get-current-repo)]
-    (when-let [content (get-file-content repo file-path)]
-      (let [data (js/Blob. ["\ufeff" (array content)] ; prepend BOM
-                           (clj->js {:type "text/plain;charset=utf-8,"}))
-            anchor (gdom/getElement "download")
-            url (js/window.URL.createObjectURL data)]
-        (.setAttribute anchor "href" url)
-        (.setAttribute anchor "download" file-path)
-        (.click anchor)))))
-
 (defn download-repo-as-html!
   "download public pages as html"
   [repo]
@@ -98,28 +48,12 @@
           (.setAttribute anchor "download" "index.html")
           (.click anchor))))))
 
-(defn- get-file-contents
-  ([repo]
-   (get-file-contents repo {:init-level 1}))
-  ([repo file-opts]
-   (let [db (db/get-db repo)]
-     (->> (d/q '[:find ?n ?fp
-                 :where
-                 [?e :block/file ?f]
-                 [?f :file/path ?fp]
-                 [?e :block/name ?n]] db)
-          (mapv (fn [[page-name file-path]]
-                  [file-path
-                   (outliner-file/tree->file-content
-                    (outliner-tree/blocks->vec-tree
-                     (db/get-page-blocks-no-cache page-name) page-name)
-                    file-opts)]))))))
-
 (defn export-repo-as-zip!
   [repo]
-  (let [files (get-file-contents repo)
-        [owner repo-name] (util/get-git-owner-and-repo repo)
-        repo-name (str owner "-" repo-name)]
+  (p/let [files (export-common-handler/<get-file-contents repo "md")
+          [owner repo-name] (util/get-git-owner-and-repo repo)
+          repo-name (str owner "-" repo-name)
+          files (map (fn [{:keys [path content]}] [path content]) files)]
     (when (seq files)
       (p/let [zipfile (zip/make-zip repo-name files repo)]
         (when-let [anchor (gdom/getElement "download")]
@@ -127,137 +61,6 @@
           (.setAttribute anchor "download" (.-name zipfile))
           (.click anchor))))))
 
-(defn- get-embed-pages-from-ast [ast]
-  (let [result (transient #{})]
-    (doseq [item ast]
-      (walk/prewalk (fn [i]
-                      (cond
-                        (and (vector? i)
-                             (= "Macro" (first i))
-                             (= "embed" (some-> (:name (second i))
-                                                (string/lower-case)))
-                             (some-> (:arguments (second i))
-                                     first
-                                     page-ref/page-ref?))
-                        (let [arguments (:arguments (second i))
-                              page-ref (first arguments)
-                              page-name (-> page-ref
-                                            (subs 2)
-                                            (#(subs % 0 (- (count %) 2)))
-                                            (string/lower-case))]
-                          (conj! result page-name)
-                          i)
-                        :else
-                        i))
-                    item))
-    (persistent! result)))
-
-(defn- get-embed-blocks-from-ast [ast]
-  (let [result (transient #{})]
-    (doseq [item ast]
-      (walk/prewalk (fn [i]
-                      (cond
-                        (and (vector? i)
-                             (= "Macro" (first i))
-                             (= "embed" (some-> (:name (second i))
-                                                (string/lower-case)))
-                             (some-> (:arguments (second i))
-                                     (first)
-                                     block-ref/string-block-ref?))
-                        (let [arguments (:arguments (second i))
-                              block-uuid (block-ref/get-string-block-ref-id (first arguments))]
-                          (conj! result block-uuid)
-                          i)
-                        :else
-                        i)) item))
-    (persistent! result)))
-
-(defn- get-block-refs-from-ast [ast]
-  (let [result (transient #{})]
-    (doseq [item ast]
-      (walk/prewalk (fn [i]
-                      (cond
-                        (and (vector? i)
-                             (= "Block_ref" (first i))
-                             (some? (second i)))
-                        (let [block-uuid (second i)]
-                          (conj! result block-uuid)
-                          i)
-                        :else
-                        i)) item))
-    (persistent! result)))
-
-(declare get-page-page&block-refs)
-(defn get-block-page&block-refs [repo block-uuid embed-pages embed-blocks block-refs]
-  (let [block (db/entity [:block/uuid (uuid block-uuid)])
-        block-content (get-blocks-contents repo (:block/uuid block))
-        format (:block/format block)
-        ast (mldoc/->edn block-content format)
-        embed-pages-new  (get-embed-pages-from-ast ast)
-        embed-blocks-new  (get-embed-blocks-from-ast ast)
-        block-refs-new (get-block-refs-from-ast ast)
-        embed-pages-diff (s/difference embed-pages-new embed-pages)
-        embed-blocks-diff (s/difference embed-blocks-new embed-blocks)
-        block-refs-diff (s/difference block-refs-new block-refs)
-        embed-pages* (s/union embed-pages-new embed-pages)
-        embed-blocks* (s/union embed-blocks-new embed-blocks)
-        block-refs* (s/union block-refs-new block-refs)
-        [embed-pages-1 embed-blocks-1 block-refs-1]
-        (->>
-         (mapv (fn [page-name]
-                 (let [{:keys [embed-pages embed-blocks block-refs]}
-                       (get-page-page&block-refs repo page-name embed-pages* embed-blocks* block-refs*)]
-                   [embed-pages embed-blocks block-refs])) embed-pages-diff)
-         (apply mapv vector) ; [[1 2 3] [4 5 6] [7 8 9]] -> [[1 4 7] [2 5 8] [3 6 9]]
-         (mapv #(apply s/union %)))
-        [embed-pages-2 embed-blocks-2 block-refs-2]
-        (->>
-         (mapv (fn [block-uuid]
-                 (let [{:keys [embed-pages embed-blocks block-refs]}
-                       (get-block-page&block-refs repo block-uuid embed-pages* embed-blocks* block-refs*)]
-                   [embed-pages embed-blocks block-refs])) (s/union embed-blocks-diff block-refs-diff))
-         (apply mapv vector)
-         (mapv #(apply s/union %)))]
-    {:embed-pages (s/union embed-pages-1 embed-pages-2 embed-pages*)
-     :embed-blocks (s/union embed-blocks-1 embed-blocks-2 embed-blocks*)
-     :block-refs (s/union block-refs-1 block-refs-2 block-refs*)}))
-
-
-(defn get-page-page&block-refs [repo page-name embed-pages embed-blocks block-refs]
-  (let [page-name* (util/page-name-sanity-lc page-name)
-        page-content (get-page-content repo page-name*)
-        format (:block/format (db/entity [:block/name page-name*]))
-        ast (mldoc/->edn page-content format)
-        embed-pages-new (get-embed-pages-from-ast ast)
-        embed-blocks-new (get-embed-blocks-from-ast ast)
-        block-refs-new (get-block-refs-from-ast ast)
-        embed-pages-diff (s/difference embed-pages-new embed-pages)
-        embed-blocks-diff (s/difference embed-blocks-new embed-blocks)
-        block-refs-diff (s/difference block-refs-new block-refs)
-        embed-pages* (s/union embed-pages-new embed-pages)
-        embed-blocks* (s/union embed-blocks-new embed-blocks)
-        block-refs* (s/union block-refs-new block-refs)
-        [embed-pages-1 embed-blocks-1 block-refs-1]
-        (->>
-         (mapv (fn [page-name]
-                 (let [{:keys [embed-pages embed-blocks block-refs]}
-                       (get-page-page&block-refs repo page-name embed-pages* embed-blocks* block-refs*)]
-                   [embed-pages embed-blocks block-refs])) embed-pages-diff)
-         (apply mapv vector)
-         (mapv #(apply s/union %)))
-        [embed-pages-2 embed-blocks-2 block-refs-2]
-        (->>
-         (mapv (fn [block-uuid]
-                 (let [{:keys [embed-pages embed-blocks block-refs]}
-                       (get-block-page&block-refs repo block-uuid embed-pages* embed-blocks* block-refs*)]
-                   [embed-pages embed-blocks block-refs])) (s/union embed-blocks-diff block-refs-diff))
-         (apply mapv vector)
-         (mapv #(apply s/union %)))]
-    {:embed-pages (s/union embed-pages-1 embed-pages-2 embed-pages*)
-     :embed-blocks (s/union embed-blocks-1 embed-blocks-2 embed-blocks*)
-     :block-refs (s/union block-refs-1 block-refs-2 block-refs*)}))
-
-
 (defn- export-file-on-mobile [data path]
   (p/catch
    (.writeFile Filesystem (clj->js {:path path
@@ -294,56 +97,21 @@
        x))
    vec-tree))
 
-(defn- safe-keywordize
-  [block]
-  (update block :block/properties
-          (fn [properties]
-            (when (seq properties)
-              (->> (filter (fn [[k _v]]
-                             (gp-property/valid-property-name? (str k))) properties)
-                   (into {}))))))
-
-(defn- blocks
-  [repo db]
-  {:version 1
-   :blocks
-   (->> (d/q '[:find (pull ?b [*])
-               :in $
-               :where
-               [?b :block/original-name]
-               [?b :block/name]] db)
-
-        (map (fn [[{:block/keys [name] :as page}]]
-               (let [whiteboard? (contains? (set (:block/type page)) "whiteboard")
-                     blocks (db/get-page-blocks-no-cache
-                             (state/get-current-repo)
-                             name
-                             {:transform? false})
-                     blocks' (if whiteboard?
-                               blocks
-                               (map (fn [b]
-                                      (let [b' (if (seq (:block/properties b))
-                                                 (update b :block/content
-                                                         (fn [content]
-                                                           (property-file/remove-properties-when-file-based
-                                                            repo (:block/format b) content)))
-                                                 b)]
-                                        (safe-keywordize b'))) blocks))
-                     children (if whiteboard?
-                                blocks'
-                                (outliner-tree/blocks->vec-tree blocks' name))
-                     page' (safe-keywordize page)]
-                 (assoc page' :block/children children))))
-        (nested-select-keys
-         [:block/id
-          :block/type
-          :block/page-name
-          :block/properties
-          :block/format
-          :block/children
-          :block/content
-          :block/created-at
-          :block/updated-at]))})
+(defn- <build-blocks
+  [repo]
+  (p/let [pages (export-common-handler/<get-all-pages repo)]
+    {:version 1
+     :blocks
+     (nested-select-keys [:block/id
+                          :block/type
+                          :block/page-name
+                          :block/properties
+                          :block/format
+                          :block/children
+                          :block/content
+                          :block/created-at
+                          :block/updated-at]
+                         pages)}))
 
 (defn- file-name [repo extension]
   (-> (string/replace repo config/local-db-prefix "")
@@ -351,25 +119,27 @@
       (str "_" (quot (util/time-ms) 1000))
       (str "." (string/lower-case (name extension)))))
 
-(defn- export-repo-as-edn-str [repo]
-  (when-let [db (db/get-db repo)]
+(defn- <export-repo-as-edn-str [repo]
+  (p/let [result (<build-blocks repo)]
+    (prn :debug :result result)
     (let [sb (StringBuffer.)]
-      (pprint/pprint (blocks repo db) (StringBufferWriter. sb))
+      (pprint/pprint result (StringBufferWriter. sb))
       (str sb))))
 
-(defn export-repo-as-edn-v2!
+(defn export-repo-as-edn!
   [repo]
-  (when-let [edn-str (export-repo-as-edn-str repo)]
-    (let [data-str (some->> edn-str
-                            js/encodeURIComponent
-                            (str "data:text/edn;charset=utf-8,"))
-          filename (file-name repo :edn)]
-      (if (mobile-util/native-platform?)
-        (export-file-on-mobile edn-str filename)
-        (when-let [anchor (gdom/getElement "download-as-edn-v2")]
-          (.setAttribute anchor "href" data-str)
-          (.setAttribute anchor "download" filename)
-          (.click anchor))))))
+  (p/let [edn-str (<export-repo-as-edn-str repo)]
+    (when edn-str
+      (let [data-str (some->> edn-str
+                              js/encodeURIComponent
+                              (str "data:text/edn;charset=utf-8,"))
+            filename (file-name repo :edn)]
+        (if (mobile-util/native-platform?)
+          (export-file-on-mobile edn-str filename)
+          (when-let [anchor (gdom/getElement "download-as-edn-v2")]
+            (.setAttribute anchor "href" data-str)
+            (.setAttribute anchor "download" filename)
+            (.click anchor)))))))
 
 (defn- nested-update-id
   [vec-tree]
@@ -380,23 +150,22 @@
        x))
    vec-tree))
 
-(defn export-repo-as-json-v2!
+(defn export-repo-as-json!
   [repo]
-  (when-let [db (db/get-db repo)]
-    (let [json-str
-          (-> (blocks repo db)
-              nested-update-id
-              clj->js
-              js/JSON.stringify)
+  (p/let [result (<build-blocks repo)
+          json-str (-> result
+                       nested-update-id
+                       clj->js
+                       js/JSON.stringify)
           filename (file-name repo :json)
           data-str (str "data:text/json;charset=utf-8,"
                         (js/encodeURIComponent json-str))]
-      (if (mobile-util/native-platform?)
-        (export-file-on-mobile json-str filename)
-        (when-let [anchor (gdom/getElement "download-as-json-v2")]
-          (.setAttribute anchor "href" data-str)
-          (.setAttribute anchor "download" filename)
-          (.click anchor))))))
+    (if (mobile-util/native-platform?)
+      (export-file-on-mobile json-str filename)
+      (when-let [anchor (gdom/getElement "download-as-json-v2")]
+        (.setAttribute anchor "href" data-str)
+        (.setAttribute anchor "download" filename)
+        (.click anchor)))))
 
 (defn export-repo-as-sqlite-db!
   [repo]
@@ -415,39 +184,25 @@
 
 ;; https://roamresearch.com/#/app/help/page/Nxz8u0vXU
 ;; export to roam json according to above spec
-(defn- roam-json [db]
-  (->> (d/q '[:find (pull ?b [*])
-              :in $
-              :where
-              [?b :block/file]
-              [?b :block/original-name]
-              [?b :block/name]] db)
-
-       (map (fn [[{:block/keys [name] :as page}]]
-              (assoc page
-                     :block/children
-                     (outliner-tree/blocks->vec-tree
-                      (db/get-page-blocks-no-cache
-                       (state/get-current-repo)
-                       name
-                       {:transform? false}) name))))
-
-       (roam-export/traverse
-        [:page/title
-         :block/string
-         :block/uid
-         :block/children])))
+(defn- <roam-data [repo]
+  (p/let [pages (export-common-handler/<get-all-pages repo)]
+    (let [non-empty-pages (remove #(empty? (:block/children %)) pages)]
+      (roam-export/traverse
+       [:page/title
+        :block/string
+        :block/uid
+        :block/children]
+       non-empty-pages))))
 
 (defn export-repo-as-roam-json!
   [repo]
-  (when-let [db (db/get-db repo)]
-    (let [json-str
-          (-> (roam-json db)
-              clj->js
-              js/JSON.stringify)
+  (p/let [data (<roam-data repo)
+          json-str (-> data
+                       bean/->js
+                       js/JSON.stringify)
           data-str (str "data:text/json;charset=utf-8,"
                         (js/encodeURIComponent json-str))]
-      (when-let [anchor (gdom/getElement "download-as-roam-json")]
-        (.setAttribute anchor "href" data-str)
-        (.setAttribute anchor "download" (file-name (str repo "_roam") :json))
-        (.click anchor)))))
+    (when-let [anchor (gdom/getElement "download-as-roam-json")]
+      (.setAttribute anchor "href" data-str)
+      (.setAttribute anchor "download" (file-name (str repo "_roam") :json))
+      (.click anchor))))

+ 41 - 41
src/main/frontend/handler/export/common.cljs

@@ -5,17 +5,18 @@
   (:refer-clojure :exclude [map filter mapcat concat remove])
   (:require [cljs.core.match :refer [match]]
             [clojure.string :as string]
-            [datascript.core :as d]
             [frontend.db :as db]
             [frontend.format.mldoc :as mldoc]
             [frontend.modules.file.core :as outliner-file]
             [frontend.modules.outliner.tree :as outliner-tree]
             [frontend.state :as state]
             [frontend.util :as util :refer [concatv mapcatv removev]]
-            [logseq.common.util :as common-util]
-            [frontend.handler.property.util :as pu]
             [malli.core :as m]
-            [malli.util :as mu]))
+            [malli.util :as mu]
+            [promesa.core :as p]
+            [frontend.persist-db.browser :as db-browser]
+            [frontend.worker.export :as worker-export]
+            [clojure.edn :as edn]))
 
 ;;; TODO: split frontend.handler.export.text related states
 (def ^:dynamic *state*
@@ -89,20 +90,30 @@
                (mapv remove-block-ast-pos
                      (mldoc/->edn content format))))))
 
-(defn get-page-content
+(defn <get-page-content
   ([page-name]
-   (get-page-content (state/get-current-repo) page-name))
+   (<get-page-content (state/get-current-repo) page-name))
   ([repo page-name]
-   (when-let [page-uuid (pu/get-page-uuid page-name)]
-     (get-blocks-contents repo page-uuid :init-level 0))))
+   (when-let [^object worker @db-browser/*worker]
+     (.block->content worker repo page-name nil
+                      (pr-str {:export-bullet-indentation (state/get-export-bullet-indentation)})))))
+
+(defn get-page-content
+  [page-name]
+  (let [repo (state/get-current-repo)
+        db (db/get-db repo)]
+    (worker-export/block->content repo db page-name
+                                  nil
+                                  {:export-bullet-indentation (state/get-export-bullet-indentation)})))
 
 (defn- page-name->ast
   [page-name]
   (when-let [content (get-page-content page-name)]
-    (let [format :markdown]
-      (removev Properties-block-ast?
-               (mapv remove-block-ast-pos
-                     (mldoc/->edn content format))))))
+    (when content
+      (let [format :markdown]
+        (removev Properties-block-ast?
+                 (mapv remove-block-ast-pos
+                       (mldoc/->edn content format)))))))
 
 (defn- update-level-in-block-ast-coll
   [block-ast-coll origin-level]
@@ -179,38 +190,27 @@
                  ast-content)))
            inline-coll)))
 
-(defn- get-file-contents
-  [repo]
-  (let [db (db/get-db repo)]
-    (->> (d/q '[:find ?fp
-                :where
-                [?e :block/file ?f]
-                [?f :file/path ?fp]] db)
-         (mapv (fn [[file-path]]
-                 [file-path
-                  (db/get-file file-path)])))))
-
-(defn- get-md-file-contents
+(defn <get-all-pages
   [repo]
-  (filterv (fn [[path _]]
-             (let [path (string/lower-case path)]
-               (re-find #"\.(?:md|markdown)$" path)))
-           (get-file-contents repo)))
+  (when-let [^object worker @db-browser/*worker]
+    (p/let [result (.get-all-pages worker repo)]
+      (edn/read-string result))))
 
-(defn get-file-contents-with-suffix
+(defn <get-all-page->content
   [repo]
-  (let [db (db/get-db repo)
-        md-files (get-md-file-contents repo)]
-    (->>
-     md-files
-     (mapv (fn [[path content]] {:path path :content content
-                                 :names (d/q '[:find [?n ?n2]
-                                               :in $ ?p
-                                               :where [?e :file/path ?p]
-                                               [?e2 :block/file ?e]
-                                               [?e2 :block/name ?n]
-                                               [?e2 :block/original-name ?n2]] db path)
-                                 :format (common-util/get-format path)})))))
+  (when-let [^object worker @db-browser/*worker]
+    (p/let [result (.get-all-page->content worker repo)]
+      (edn/read-string result))))
+
+(defn <get-file-contents
+  [repo suffix]
+  (p/let [page->content (<get-all-page->content repo)]
+    (clojure.core/map (fn [[page-title content]]
+                        {:path (str page-title "."suffix)
+                         :content content
+                         :title page-title
+                         :format :markdown})
+                      page->content)))
 
 ;;; utils (ends)
 

+ 19 - 13
src/main/frontend/handler/export/opml.cljs

@@ -15,7 +15,8 @@
             [goog.dom :as gdom]
             [hiccups.runtime :as h]
             [frontend.format.mldoc :as mldoc]
-            [promesa.core :as p]))
+            [promesa.core :as p]
+            [frontend.config :as config]))
 
 ;;; *opml-state*
 (def ^:private ^:dynamic
@@ -449,25 +450,30 @@
          format (or (:block/format first-block) (state/get-preferred-format))]
      (export-helper content format options :title title))))
 
-(defn export-files-as-opml
+(defn- export-files-as-opml
   "options see also `export-blocks-as-opml`"
   [files options]
   (mapv
-   (fn [{:keys [path content names format]}]
-     (when (first names)
+   (fn [{:keys [path content title format]}]
+     (when (and title (not (string/blank? content)))
        (util/profile (print-str :export-files-as-opml path)
-                     [path (export-helper content format options :title (first names))])))
+                     [path (export-helper content format options :title title)])))
    files))
 
 (defn export-repo-as-opml!
   [repo]
-  (when-let [files (common/get-file-contents-with-suffix repo)]
-    (let [files (export-files-as-opml files nil)
-          zip-file-name (str repo "_opml_" (quot (util/time-ms) 1000))]
-      (p/let [zipfile (zip/make-zip zip-file-name files repo)]
-        (when-let [anchor (gdom/getElement "export-as-opml")]
-          (.setAttribute anchor "href" (js/window.URL.createObjectURL zipfile))
-          (.setAttribute anchor "download" (.-name zipfile))
-          (.click anchor))))))
+  (p/let [files (common/<get-file-contents repo "opml")]
+    (when (seq files)
+      (let [repo (-> repo
+                     (string/replace config/db-version-prefix "")
+                     (string/replace config/local-db-prefix ""))
+            files (->> (export-files-as-opml files nil)
+                       (clojure.core/remove nil?))
+            zip-file-name (str repo "_opml_" (quot (util/time-ms) 1000))]
+        (p/let [zipfile (zip/make-zip zip-file-name files repo)]
+          (when-let [anchor (gdom/getElement "export-as-opml")]
+            (.setAttribute anchor "href" (js/window.URL.createObjectURL zipfile))
+            (.setAttribute anchor "download" (.-name zipfile))
+            (.click anchor)))))))
 
 ;;; export fns (ends)

+ 17 - 13
src/main/frontend/handler/export/text.cljs

@@ -13,7 +13,8 @@
             [goog.dom :as gdom]
             [frontend.format.mldoc :as mldoc]
             [malli.core :as m]
-            [promesa.core :as p]))
+            [promesa.core :as p]
+            [frontend.config :as config]))
 
 ;;; block-ast, inline-ast -> simple-ast
 
@@ -522,22 +523,25 @@
   "options see also `export-blocks-as-markdown`"
   [files options]
   (mapv
-   (fn [{:keys [path content names format]}]
-     (when (first names)
-       (util/profile (print-str :export-files-as-markdown path)
-                     [path (export-helper content format options)])))
+   (fn [{:keys [path title content]}]
+     (util/profile (print-str :export-files-as-markdown title)
+                   [(or path title) (export-helper content :markdown options)]))
    files))
 
 (defn export-repo-as-markdown!
   "TODO: indent-style and remove-options"
   [repo]
-  (when-let [files (util/profile :get-file-content (common/get-file-contents-with-suffix repo))]
-    (let [files (export-files-as-markdown files nil)
-          zip-file-name (str repo "_markdown_" (quot (util/time-ms) 1000))]
-      (p/let [zipfile (zip/make-zip zip-file-name files repo)]
-        (when-let [anchor (gdom/getElement "export-as-markdown")]
-          (.setAttribute anchor "href" (js/window.URL.createObjectURL zipfile))
-          (.setAttribute anchor "download" (.-name zipfile))
-          (.click anchor))))))
+  (p/let [files (util/profile :get-file-content (common/<get-file-contents repo "md"))]
+    (when (seq files)
+      (let [files (export-files-as-markdown files nil)
+            repo (-> repo
+                     (string/replace config/db-version-prefix "")
+                     (string/replace config/local-db-prefix ""))
+            zip-file-name (str repo "_markdown_" (quot (util/time-ms) 1000))]
+        (p/let [zipfile (zip/make-zip zip-file-name files repo)]
+          (when-let [anchor (gdom/getElement "export-as-markdown")]
+            (.setAttribute anchor "href" (js/window.URL.createObjectURL zipfile))
+            (.setAttribute anchor "download" (.-name zipfile))
+            (.click anchor)))))))
 
 ;;; export fns (ends)

+ 0 - 1
src/main/frontend/handler/property/util.cljs

@@ -3,7 +3,6 @@
   Some fns like lookup and get-property were written to easily be backwards
   compatible with file graphs"
   (:require [frontend.state :as state]
-            [logseq.common.util :as common-util]
             [frontend.db :as db]
             [logseq.db.frontend.property :as db-property]))
 

+ 2 - 1
src/main/frontend/handler/repo.cljs

@@ -418,7 +418,8 @@
      (global-config-handler/restore-global-config!))
     ;; Don't have to unlisten the old listener, as it will be destroyed with the conn
    (ui-handler/add-style-if-exists!)
-   (state/set-db-restoring! false)))
+   (when-not config/publishing?
+     (state/set-db-restoring! false))))
 
 (defn rebuild-index!
   [url]

+ 3 - 25
src/main/frontend/handler/whiteboard.cljs

@@ -18,8 +18,7 @@
             [clojure.set :as set]
             [clojure.string :as string]
             [cljs-bean.core :as bean]
-            [logseq.db.sqlite.util :as sqlite-util]
-            [clojure.data :as data]))
+            [logseq.db.sqlite.util :as sqlite-util]))
 
 (defn js->clj-keywordize
   [obj]
@@ -255,39 +254,18 @@
         blocks (:block/_page react-page)]
     (whiteboard-clj->tldr react-page blocks)))
 
-(defn- get-whiteboard-blocks
-  "Given a page, return all the logseq blocks (exclude all shapes)"
-  [page-name]
-  (let [blocks (model/get-page-blocks-no-cache page-name)]
-    (remove pu/shape-block? blocks)))
-
-(defn- get-last-root-block
-  "Get the last root Logseq block in the page. Main purpose is to calculate the new :block/left id"
-  [page-name]
-  (let [page-id (:db/id (model/get-page page-name))
-        blocks (get-whiteboard-blocks page-name)
-        root-blocks (filter (fn [block] (= page-id (:db/id (:block/parent block)))) blocks)
-        root-block-left-ids (->> root-blocks
-                                 (map (fn [block] (get-in block [:block/left :db/id] nil)))
-                                 (remove nil?)
-                                 (set))
-        blocks-with-no-next (remove #(root-block-left-ids (:db/id %)) root-blocks)]
-    (when (seq blocks-with-no-next) (first blocks-with-no-next))))
-
 (defn <add-new-block!
   [page-name content]
   (p/let [repo (state/get-current-repo)
           new-block-id (db/new-block-id)
           page-entity (model/get-page page-name)
-          last-root-block (or (get-last-root-block page-name) page-entity)
           tx (sqlite-util/block-with-timestamps
-              {:block/left (select-keys last-root-block [:db/id])
-               :block/uuid new-block-id
+              {:block/uuid new-block-id
                :block/content (or content "")
                :block/format :markdown
                :block/page {:block/name (util/page-name-sanity-lc page-name)
                             :block/original-name page-name}
-               :block/parent {:block/name page-name}})
+               :block/parent (:db/id page-entity)})
           _ (db/transact! repo [tx] {:whiteboard/transact? true})]
     new-block-id))
 

+ 8 - 2
src/main/frontend/handler/worker.cljs

@@ -46,5 +46,11 @@
         (fn [event]
           (let [data (.-data event)]
             (when-not (= (.-type data) "RAW")
-              (let [[e payload] (bean/->clj data)]
-                (handle (keyword e) wrapped-worker payload)))))))
+              ;; Log thrown exceptions from comlink
+              ;; https://github.com/GoogleChromeLabs/comlink/blob/dffe9050f63b1b39f30213adeb1dd4b9ed7d2594/src/comlink.ts#L223-L236
+              (if (and (= "HANDLER" (.-type data)) (= "throw" (.-name data)))
+                (if (.-isError (.-value data))
+                  (js/console.error "Unexpected webworker error:" (-> data bean/->clj (get-in [:value :value])))
+                  (js/console.error "Unexpected webworker error:" data))
+                (let [[e payload] (bean/->clj data)]
+                  (handle (keyword e) wrapped-worker payload))))))))

+ 2 - 2
src/main/frontend/persist_db/browser.cljs

@@ -65,8 +65,8 @@
   (when-not util/node-test?
     (let [worker-url (if (util/electron?)
                        "js/db-worker.js"
-                       "/static/js/db-worker.js")
-          worker (js/Worker. (str worker-url "?electron=" (util/electron?)))
+                       "static/js/db-worker.js")
+          worker (js/Worker. (str worker-url "?electron=" (util/electron?) "&publishing=" config/publishing?))
           wrapped-worker (Comlink/wrap worker)]
       (worker-handler/handle-message! worker wrapped-worker)
       (reset! *worker wrapped-worker)

+ 10 - 24
src/main/frontend/publishing.cljs

@@ -24,10 +24,7 @@
             [frontend.persist-db.browser :as db-browser]
             [promesa.core :as p]
             [frontend.handler.repo :as repo-handler]
-            [datascript.core :as d]
-            [frontend.handler.ui :as ui-handler]
-            [frontend.storage :as storage]
-            [frontend.db.persist :as db-persist]))
+            [frontend.handler.ui :as ui-handler]))
 
 ;; The publishing site should be as thin as possible.
 ;; Both files and git libraries can be removed.
@@ -59,26 +56,14 @@
   (when-let [data js/window.logseq_db]
     (let [repo (-> @state/state :config keys first)]
       (state/set-current-repo! repo)
-      (p/do!
-       (p/let [cached-data-length (storage/get :db-cached-str-length)]
-         (when (nil? cached-data-length)
-           (storage/set :db-cached-str-length (count data)))
-         (when (and cached-data-length (not= cached-data-length (count data)))
-           ;; delete old graph after re-published
-           (db-persist/delete-graph! repo)))
-
-       (repo-handler/restore-and-setup-repo! repo)
-
-       (when-not (db/entity :db/transacted?)
-         (let [data (unescape-html data)
-               db (db/string->db data)
-               datoms (d/datoms db :eavt)]
-           (db/transact! repo
-                         (conj (vec datoms)
-                               {:db/ident :db/transacted? :db/transacted? true})
-                         {:init-db? true
-                          :new-graph? true})))
-       (ui-handler/re-render-root!)))))
+      (p/let [_ (repo-handler/restore-and-setup-repo! repo)
+              _ (let [data (unescape-html data)
+                      db (db/string->db data)
+                      datoms (d/datoms db :eavt)]
+                  (db/transact! repo datoms {:init-db? true
+                                             :new-graph? true}))]
+        (state/set-db-restoring! false)
+        (ui-handler/re-render-root!)))))
 
 (defn restore-state!
   []
@@ -120,6 +105,7 @@
   (events/run!)
   (p/do!
    (db-browser/start-db-worker!)
+   (state/set-db-restoring! true)
    (start)
    (restore-from-transit-str!)))
 

+ 2 - 2
src/main/frontend/routes.cljs

@@ -12,8 +12,8 @@
             [frontend.extensions.zotero :as zotero]
             [frontend.components.bug-report :as bug-report]
             [frontend.components.user.login :as login]
-            [frontend.components.imports :as imports]
-            [logseq.shui.demo :as shui]))
+            [logseq.shui.demo :as shui]
+            [frontend.components.imports :as imports]))
 
 ;; http://localhost:3000/#?anchor=fn.1
 (def routes

+ 12 - 10
src/main/frontend/state.cljs

@@ -1071,7 +1071,7 @@ Similar to re-frame subscriptions"
 
 (defn set-selection-start-block!
   [start-block]
-  (swap! state assoc :selection/start-block start-block))
+  (set-state! :selection/start-block start-block))
 
 (defn set-selection-blocks!
   ([blocks]
@@ -1129,18 +1129,16 @@ Similar to re-frame subscriptions"
                    distinct
                    util/sort-by-height
                    vec)]
-    (swap! state assoc
-           :selection/mode true
-           :selection/blocks blocks
-           :selection/direction direction)))
+    (set-state! :selection/mode true)
+    (set-state! :selection/blocks blocks)
+    (set-state! :selection/direction direction)))
 
 (defn drop-selection-block!
   [block]
-  (swap! state assoc
-         :selection/mode true
-         :selection/blocks (-> (remove #(= block %) (get-selection-blocks))
-                               util/sort-by-height
-                               vec)))
+  (set-state! :selection/mode true)
+  (set-state! :selection/blocks (-> (remove #(= block %) (get-selection-blocks))
+                                    util/sort-by-height
+                                    vec)))
 
 (defn drop-last-selection-block!
   []
@@ -2015,6 +2013,10 @@ Similar to re-frame subscriptions"
   []
   (false? (sub [:electron/user-cfgs :git/disable-auto-commit?])))
 
+(defn get-git-commit-on-close-enabled?
+  []
+  (sub [:electron/user-cfgs :git/commit-on-close?]))
+
 (defn set-last-key-code!
   [key-code]
   (set-state! :editor/last-key-code key-code))

+ 67 - 0
src/main/frontend/worker/export.cljs

@@ -0,0 +1,67 @@
+(ns frontend.worker.export
+  "Export data"
+  (:require [logseq.db :as ldb]
+            [logseq.outliner.tree :as otree]
+            [frontend.worker.file.core :as worker-file]
+            [datascript.core :as d]
+            [logseq.common.util :as common-util]
+            [logseq.graph-parser.property :as gp-property]))
+
+(defn block->content
+  "Converts a block including its children (recursively) to plain-text."
+  [repo db root-block-uuid-or-page-name tree->file-opts context]
+  (let [root-block-uuid (or
+                         (and (uuid? root-block-uuid-or-page-name) root-block-uuid-or-page-name)
+                         (:block/uuid (d/entity db [:block/name (common-util/page-name-sanity-lc
+                                                                 root-block-uuid-or-page-name)])))
+        init-level (or (:init-level tree->file-opts)
+                       (if (uuid? root-block-uuid-or-page-name) 1 0))
+        blocks (ldb/get-block-and-children repo db root-block-uuid)
+        tree (otree/blocks->vec-tree repo db blocks (str root-block-uuid))]
+    (worker-file/tree->file-content repo db tree
+                                    (assoc tree->file-opts :init-level init-level)
+                                    context)))
+
+(defn- safe-keywordize
+  [block]
+  (update block :block/properties
+          (fn [properties]
+            (when (seq properties)
+              (->> (filter (fn [[k _v]]
+                             (gp-property/valid-property-name? (str k))) properties)
+                   (into {}))))))
+
+(defn get-all-pages
+  "Get all pages and their children blocks."
+  [repo db]
+  (->> (d/q '[:find (pull ?b [*])
+              :in $
+              :where
+              [?b :block/original-name]
+              [?b :block/name]] db)
+
+       (map (fn [[{:block/keys [name] :as page}]]
+              (let [whiteboard? (contains? (set (:block/type page)) "whiteboard")
+                    blocks (ldb/get-page-blocks db name {})
+                    blocks' (if whiteboard?
+                              blocks
+                              (map (fn [b]
+                                     (let [b' (if (seq (:block/properties b))
+                                                (update b :block/content
+                                                        (fn [content]
+                                                          (gp-property/remove-properties (:block/format b) content)))
+                                                b)]
+                                       (safe-keywordize b'))) blocks))
+                    children (if whiteboard?
+                               blocks'
+                               (otree/blocks->vec-tree repo db blocks' name))
+                    page' (safe-keywordize page)]
+                (assoc page' :block/children children))))))
+
+(defn get-all-page->content
+  [repo db]
+  (->> (d/datoms db :avet :block/name)
+       (map (fn [d]
+              (let [e (d/entity db (:e d))]
+                [(:block/original-name e)
+                 (block->content repo db (:v d) {} {})])))))

+ 5 - 4
src/main/frontend/worker/file/core.cljs

@@ -7,7 +7,8 @@
             [datascript.core :as d]
             [logseq.db :as ldb]
             [frontend.worker.date :as worker-date]
-            [frontend.worker.util :as worker-util]))
+            [frontend.worker.util :as worker-util]
+            [logseq.db.sqlite.util :as sqlite-util]))
 
 (defonce *writes (atom {}))
 (defonce *request-id (atom 0))
@@ -44,7 +45,8 @@
 (defn transform-content
   [repo db {:block/keys [collapsed? format pre-block? content left page parent properties] :as b} level {:keys [heading-to-list?]} context]
   (let [block-ref-not-saved? (and (seq (:block/_refs (d/entity db (:db/id b))))
-                                  (not (string/includes? content (str (:block/uuid b)))))
+                                  (not (string/includes? content (str (:block/uuid b))))
+                                  (not (sqlite-util/db-based-graph? repo)))
         heading (:heading properties)
         markdown? (= :markdown format)
         content (or content "")
@@ -58,8 +60,7 @@
                     (str content "\n"))
 
                   :else
-                  (let [
-                        ;; first block is a heading, Markdown users prefer to remove the `-` before the content
+                  (let [;; first block is a heading, Markdown users prefer to remove the `-` before the content
                         markdown-top-heading? (and markdown?
                                                    (= parent page left)
                                                    heading)

+ 39 - 39
src/main/logseq/api.cljs

@@ -606,45 +606,45 @@
   (fn [block-uuid-or-page-name content ^js opts]
     (when (string/blank? block-uuid-or-page-name)
       (throw (js/Error. "Page title or block UUID shouldn't be empty.")))
-    (let [{:keys [before sibling focus customUUID properties autoOrderedList]} (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 (not (db/entity [:block/name page-name])))
-                                   (page-handler/create! block-uuid-or-page-name {:create-first-block? false}))
-          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 (db-model/get-by-parent-&-left (db/get-db)
-                                                                                    (:db/id block)
-                                                                                    (: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])
-          before?                (if (and (false? sibling?) before? (not insert-at-first-child?))
-                                   false
-                                   before?)
-          new-block              (editor-handler/api-insert-new-block!
-                                  content
-                                  {:block-uuid    block-uuid'
-                                   :sibling?      sibling?
-                                   :before?       before?
-                                   :edit-block?   edit-block?
-                                   :page          page-name
-                                   :custom-uuid   custom-uuid
-                                   :ordered-list? (if (boolean? autoOrderedList) autoOrderedList false)
-                                   :properties    (merge properties
+    (p/let [{:keys [before sibling focus customUUID properties autoOrderedList]} (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 (not (db/entity [:block/name page-name])))
+                                     (page-handler/<create! block-uuid-or-page-name {:create-first-block? false}))
+            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 (db-model/get-by-parent-&-left (db/get-db)
+                                                                                      (:db/id block)
+                                                                                      (: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])
+            before?                (if (and (false? sibling?) before? (not insert-at-first-child?))
+                                     false
+                                     before?)
+            new-block              (editor-handler/api-insert-new-block!
+                                    content
+                                    {:block-uuid  block-uuid'
+                                     :sibling?    sibling?
+                                     :before?     before?
+                                     :edit-block? edit-block?
+                                     :page        page-name
+                                     :custom-uuid custom-uuid
+                                     :ordered-list? (if (boolean? autoOrderedList) autoOrderedList false)
+                                     :properties  (merge properties
                                                          (when custom-uuid {:id custom-uuid}))})]
       (bean/->js (sdk-utils/normalize-keyword-for-json new-block)))))
 

+ 0 - 1
src/resources/dicts/de.edn

@@ -538,7 +538,6 @@
  :settings-page/enable-tooltip "Tooltips"
  :settings-page/export-theme "Theme exportieren"
  :settings-page/git-commit-delay "Anzahl Sekunden für Git Auto Commit"
- :settings-page/git-confirm "Sie müssen die App neu starten, nachdem Sie die Git-Einstellungen angepasst haben."
  :settings-page/git-switcher-label "Git Auto Commit aktivieren"
  :settings-page/home-default-page "Standard-Homepage einrichten"
  :settings-page/login-prompt "Um vor allen anderen auf neue Funktionen zugreifen zu können, müssen Sie ein Open Collective Sponsor oder Backer von Logseq sein und sich daher zuerst anmelden."

+ 1 - 1
src/resources/dicts/en.edn

@@ -262,9 +262,9 @@
  :settings-page/git-desc-1 "To view page's edit history, click the three horizontal dots in the top-right corner and select \"View page history\"."
  :settings-page/git-desc-2 "For professional users, Logseq also supports using "
  :settings-page/git-desc-3 " for version control. Use Git at your own risk as general Git issues are not supported by the Logseq team."
+ :settings-page/git-commit-on-close "Git commit on window close"
  :settings-page/git-switcher-label "Enable Git auto commit"
  :settings-page/git-commit-delay "Git auto commit seconds"
- :settings-page/git-confirm "You need to restart the app after updating the Git settings."
  :settings-page/edit-config-edn "Edit config.edn"
  :settings-page/edit-global-config-edn "Edit global config.edn"
  :settings-page/edit-custom-css "Edit custom.css"

+ 1 - 1
src/resources/dicts/es.edn

@@ -614,10 +614,10 @@
  :settings-page/enable-whiteboards                  "Pizarras"
  :settings-page/export-theme                        "Tema exportación"
  :settings-page/git-commit-delay                    "Segundos para Git auto commit"
- :settings-page/git-confirm                         "Debe reiniciar la aplicación después de actualizar las opciones de Git."
  :settings-page/git-desc-1                          "Para ver el historial de edición de la página, da clic en los tres puntos horizontales en la esquina superior derecha y selecciona \"Ver historial de página\"."
  :settings-page/git-desc-2                          "Para usuarios profesionales, Logseq también es compatible con"
  :settings-page/git-desc-3                          " para control de versiones. Usa Git bajo tu propio riesgo ya que problemas generales con Git no son respaldados por el equipo de Logseq."
+ :settings-page/git-commit-on-close  "Git auto commit"
  :settings-page/git-switcher-label                  "Habilitar Git auto commit"
  :settings-page/git-tip                             "Si tienes Logseq Sync habilitado, puedes ver el historial de edición de la página directamente. Esta sección es solo para conocedores de tecnología."
  :settings-page/home-default-page                   "Establecer página de inicio"

+ 2 - 14
src/resources/dicts/fr.edn

@@ -142,7 +142,7 @@
     :linked-references/filter-excludes "Exclut : "
     :linked-references/filter-heading "Filtrer"
     :linked-references/filter-includes "Inclut : "
-    :linked-references/reference-count (fn [filtered-count total] (cond (= filtered-count nil) (cond (= total 0) "Aucune référence liée" (= total 1) "1 référence liée" :else (str total " références liées")) (= filtered-count 1) (str "1 référence liée / " total) :else (str filtered-count " références liées / " total) ))
+    :linked-references/reference-count (fn [filtered-count total] (str filtered-count (when filtered-count (if (= filtered-count 1) " référence liée" " références liées")) " parmi " total))
     :linked-references/filter-search "Rechercher dans les pages liées"
  :on-boarding/add-graph "Ajouter un graphe"
     :on-boarding/demo-graph "Il s'agit d'un graphe de démo, les changements ne seront pas enregistrés à moins que vous n'ouvriez un dossier local."
@@ -234,7 +234,6 @@
     :settings-page/enable-whiteboards "Tableaux blancs"
     :settings-page/export-theme "Exporter le thème"
     :settings-page/git-commit-delay "Délai (secondes) des commits Git automatiques"
-    :settings-page/git-confirm "Vous devez redémarrer l'application après avoir mis à jour le dossier Git"
     :settings-page/git-switcher-label "Activer les commits Git automatiques"
     :settings-page/home-default-page "Régler la page d'accueil par défaut"
     :settings-page/login-prompt "Pour accéder aux nouvelles fonctionnalités avant tout le monde, vous devez être sponsor ou \"backer\" (contributeur) sur Open Collective, puis vous connecter."
@@ -769,15 +768,4 @@
     :settings-page/auto-chmod "Automatiquement changer les permissions du fichier"
     :settings-page/auto-chmod-desc "Désactiver pour permettre l'édition par plusieurs utilisateurs avec les permissions données par l'appartenance au groupe."
     :settings-page/tab-keymap "Raccourcis"
-    :unlinked-references/reference-count (fn [total]
-                                           (cond
-                                             (or (nil? total) (= total ""))
-                                             "Références non liées"
-                                             (= total 0)
-                                             "Aucune référence non liée"
-                                             (= total 1)
-                                             "1 référence non liée"
-                                             (> total 1)
-                                             (str total " références non liées")
-                                             :else
-                                             "Références non liées"))}
+    :unlinked-references/reference-count  (fn [total] (str total (if (= total 1) " référence non liée" " références non liées")))}

+ 0 - 1
src/resources/dicts/id.edn

@@ -235,7 +235,6 @@
  :settings-page/git-desc-3 " untuk kontrol versi. Gunakan Git dengan risiko Anda sendiri karena masalah umum Git tidak didukung oleh tim Logseq."
  :settings-page/git-switcher-label "Aktifkan komit otomatis Git"
  :settings-page/git-commit-delay "Detik komit otomatis Git"
- :settings-page/git-confirm "Anda perlu me-restart aplikasi setelah memperbarui pengaturan Git."
  :settings-page/edit-config-edn "Sunting config.edn"
  :settings-page/edit-global-config-edn "Sunting global config.edn"
  :settings-page/edit-custom-css "Sunting custom.css"

+ 0 - 1
src/resources/dicts/it.edn

@@ -77,7 +77,6 @@
  :content/copy-block-emebed "Copia blocco incorporato"
  :content/open-in-sidebar "Apri nel pannello laterale"
  :content/click-to-edit "Clicca per modificare"
- :settings-page/git-confirm "Devi riavviare l'app dopo aver aggiornato le impostazioni di Git."
  :settings-page/git-switcher-label "Commit automatico"
  :settings-page/git-commit-delay "Secondi per commit automatico"
  :settings-page/edit-config-edn "Modifica config.edn"

+ 0 - 1
src/resources/dicts/ja.edn

@@ -244,7 +244,6 @@
  :settings-page/git-desc-3 " の利用も用意しています。Gitの利用はご自身の責任で行ってください。一般的なGitの問題について、Logseqチームはサポートしません。"
  :settings-page/git-switcher-label "Gitの自動コミットを有効化"
  :settings-page/git-commit-delay "Gitの自動コミット間隔(秒)"
- :settings-page/git-confirm "Git設定を更新するにはアプリを再起動する必要があります。"
  :settings-page/edit-config-edn "config.ednを編集"
  :settings-page/edit-global-config-edn "グローバルなconfig.ednを編集"
  :settings-page/edit-custom-css "custom.cssを編集"

+ 0 - 1
src/resources/dicts/ko.edn

@@ -78,7 +78,6 @@
  :content/copy-block-emebed "블록 임베드 복사"
  :content/open-in-sidebar "사이드바에서 열기"
  :content/click-to-edit "클릭하여 수정"
- :settings-page/git-confirm "Git 설정을 변경한 뒤 앱을 재시작해야 합니다."
  :settings-page/git-switcher-label "Git 자동 커밋 설정"
  :settings-page/git-commit-delay "Git 자동 커밋 간격 (초)"
  :settings-page/edit-config-edn "config.edn 수정"

+ 1 - 2
src/resources/dicts/nb-no.edn

@@ -79,7 +79,6 @@
  :content/copy-block-emebed "Kopier innebygging av blokk"
  :content/open-in-sidebar "Åpne i sidefeltet"
  :content/click-to-edit "Klikk for å redigere"
- :settings-page/git-confirm "Du må starte appen på nytt etter å ha oppdatert Git innstillingene."
  :settings-page/git-switcher-label "Skru på Git auto commit"
  :settings-page/git-commit-delay "Git auto commit sekunder"
  :settings-page/edit-config-edn "Rediger config.edn for nåværende repo"
@@ -754,7 +753,7 @@
  :settings-page/auto-chmod-desc "Deaktiver for å tillate redigering av flere brukere med tillatelser gitt av gruppemedlemskap."
  :settings-page/tab-keymap "Tastatur"
  :whiteboard/toggle-pen-mode "Veksle pen-modus"
- 
+
  :command.command-palette/toggle "Søk kommandoer"
  :command.go/search-in-page "Søk blokker på side"
  :command.ui/cycle-color "Veksle farge"

+ 0 - 1
src/resources/dicts/nl.edn

@@ -191,7 +191,6 @@
  :settings-page/enable-tooltip "Tooltips inschakelen"
  :settings-page/export-theme "Exporteer thema"
  :settings-page/git-commit-delay "Git auto commit seconden"
- :settings-page/git-confirm "Je moet de app opnieuw opstarten nadat je de Git instellingen hebt aangepast."
  :settings-page/git-switcher-label "Git auto commit inschakelen"
  :settings-page/home-default-page "De standaard startpagina instellen"
  :settings-page/network-proxy "Netwerk proxy"

+ 0 - 1
src/resources/dicts/pl.edn

@@ -82,7 +82,6 @@
  :content/copy-block-emebed "Kopiuj blok jako embed"
  :content/open-in-sidebar "Otwórz w panelu bocznym"
  :content/click-to-edit "Kliknij, aby edytować"
- :settings-page/git-confirm "Musisz uruchomić ponownie aplikację żeby zastosować zmiany w ustawieniach Gita."
  :settings-page/git-switcher-label "Włącz opcję autocommit w Git"
  :settings-page/git-commit-delay "Wykonaj commit co każde [s.]"
  :settings-page/edit-config-edn "Edytuj config.edn"

+ 0 - 1
src/resources/dicts/pt-br.edn

@@ -239,7 +239,6 @@
  :settings-page/git-desc-3 " para controle de versão. Use o Git por sua própria conta e risco, uma vez que questões gerais do Git não são suportadas pela equipe do Logseq."
  :settings-page/git-switcher-label "Ativar confirmação automática do Git"
  :settings-page/git-commit-delay "Segundos para confirmação automática do Git"
- :settings-page/git-confirm "Você precisa reiniciar o aplicativo após atualizar as configurações do Git."
  :settings-page/edit-config-edn "Editar config.edn"
  :settings-page/edit-global-config-edn "Editar config.edn global"
  :settings-page/edit-custom-css "Editar custom.css"

+ 0 - 1
src/resources/dicts/pt-pt.edn

@@ -115,7 +115,6 @@
  :content/delete-ref "Apagar esta referência"
  :content/open-in-sidebar "Abrir na barra lateral"
  :content/click-to-edit "Clicar para editar"
- :settings-page/git-confirm "É necessário reiniciar a aplicação após atualizar as definições do Git."
  :settings-page/git-switcher-label "Ativar o auto commit do Git"
  :settings-page/git-commit-delay "Segundos entre cada auto commit"
  :settings-page/edit-config-edn "Editar config.edn"

+ 0 - 1
src/resources/dicts/ru.edn

@@ -146,7 +146,6 @@
  :context-menu/input-template-name                     "Как назовём шаблон?"
  :context-menu/template-include-parent-block           "Включить родительский блок в шаблон?"
  :context-menu/template-exists-warning                 "Шаблон уже существует!"
- :settings-page/git-confirm                            "Необходимо перезапустить приложение после изменения настроек Git."
  :settings-page/git-switcher-label                     "Включить автокоммит в Git"
  :settings-page/git-commit-delay                       "Задержка автокоммита Git в секундах"
  :settings-page/edit-config-edn                        "Редактировать config.edn"

+ 0 - 1
src/resources/dicts/sk.edn

@@ -240,7 +240,6 @@
  :settings-page/git-desc-3                         " pre správu verzií. Používajte Git na vlastné riziko, pretože všeobecné problémy s Git nie sú podporované tímom Logseq."
  :settings-page/git-switcher-label                 "Povoliť automatický zápis do Git"
  :settings-page/git-commit-delay                   "Automatický zápis do Git po sekundách"
- :settings-page/git-confirm                        "Po aktualizácii nastavení Git je potrebné reštartovať aplikáciu."
  :settings-page/edit-config-edn                    "Upraviť config.edn"
  :settings-page/edit-global-config-edn             "Upraviť globálny config.edn"
  :settings-page/edit-custom-css                    "Upraviť custom.css"

+ 0 - 1
src/resources/dicts/tr.edn

@@ -262,7 +262,6 @@
  :settings-page/git-desc-3 " kullanımını da destekler. Genel Git sorunları Logseq ekibi tarafından desteklenmediğinden Git'i kullanmanın riski size aittir."
  :settings-page/git-switcher-label "Otomatik git commit'i etkinleştir"
  :settings-page/git-commit-delay "Otomatik git commit saniyesi"
- :settings-page/git-confirm "Git ayarlarını güncelledikten sonra uygulamayı yeniden başlatmanız gerekiyor."
  :settings-page/edit-config-edn "config.edn dosyasını düzenle"
  :settings-page/edit-global-config-edn "Genel config.edn dosyasını düzenle"
  :settings-page/edit-custom-css "custom.css dosyasını düzenle"

+ 0 - 1
src/resources/dicts/uk.edn

@@ -137,7 +137,6 @@
  :context-menu/input-template-name "Як назвемо шаблон?"
  :context-menu/template-include-parent-block "Включити батьківський блок у шаблон?"
  :context-menu/template-exists-warning "Шаблон вже існує!"
- :settings-page/git-confirm "Вам потрібно перезапустити програму після оновлення налаштувань Git."
  :settings-page/git-switcher-label "Увімкнути Git авто commit"
  :settings-page/git-commit-delay "Секунди Git авто commit"
  :settings-page/edit-config-edn "Редагувати config.edn"

+ 0 - 1
src/resources/dicts/zh-cn.edn

@@ -166,7 +166,6 @@
  :settings-page/edit-custom-css "编辑 custom.css (当前库)"
  :settings-page/custom-configuration "自定义配置"
  :settings-page/custom-theme "自定义主题"
- :settings-page/git-confirm "更新 Git 设置后,需要重启应用"
  :settings-page/git-switcher-label "开启 Git 自动 commit"
  :settings-page/git-commit-delay "Git 自动 commit 间隔秒数"
  :settings-page/preferred-outdenting "逻辑缩进"

+ 0 - 1
src/resources/dicts/zh-hant.edn

@@ -113,7 +113,6 @@
  :content/copy-block-emebed "複製嵌入區塊"
  :content/open-in-sidebar "在側邊欄中打開"
  :content/click-to-edit "點擊以編輯"
- :settings-page/git-confirm "在更新 Git 設置後,您需要重新啟動應用程式。"
  :settings-page/git-switcher-label "啟用 Git 自動提交"
  :settings-page/git-commit-delay "Git 自動提交間隔"
  :settings-page/edit-config-edn "編輯 config.edn"

+ 10 - 51
src/test/frontend/handler/export_test.cljs

@@ -130,47 +130,6 @@
 	- 4")
     "97a00e55-48c3-48d8-b9ca-417b16e3a616"))
 
-(deftest export-blocks-as-markdown-no-indent
-  (are [expect content]
-      (= (string/trim expect)
-         (string/trim (#'export-text/export-helper (string/trim content) :markdown {:indent-style "no-indent"})))
-      "
-1
-2
-3
-4
-5"
-      "
-- 1
-  2
-  3
-  - 4
-    5"
-"
-some inner code
-```jsx
-import React;
-
-function main() {
-  return 0;
-}
-
-export default main;
-```
-"
-    "
-- some inner code
-  - ```jsx
-    import React;
-
-    function main() {
-      return 0;
-    }
-
-    export default main;
-    ```
-"))
-
 
 (deftest-async export-files-as-markdown
   (p/do!
@@ -183,13 +142,13 @@ export default main;
        [["pages/page2.md" "- 3\n\t- 1\n\t\t- 2\n\t\t\t- 3\n\t\t\t- 3\n\t- 4\n"]]
        [{:path "pages/page2.md" :content (:file/content (nth test-files 1)) :names ["page2"] :format :markdown}])))
 
-(deftest-async export-repo-as-edn-str
-  (p/do!
-   (let [edn-output (edn/read-string
-                     (@#'export/export-repo-as-edn-str (state/get-current-repo)))]
-     (is (= #{:version :blocks} (set (keys edn-output)))
-         "Correct top-level keys")
-     (is (= (sort (concat (map :block/original-name default-db/built-in-pages)
-                          ["page1" "page2"]))
-            (sort (map :block/page-name (:blocks edn-output))))
-         "Correct pages"))))
+;; Disabled because this requires db worker
+#_(deftest-async export-repo-as-edn-str
+    (p/let [result (@#'export/<export-repo-as-edn-str (state/get-current-repo))
+                      edn-output (edn/read-string result)]
+          (is (= #{:version :blocks} (set (keys edn-output)))
+                      "Correct top-level keys")
+              (is (= (sort (concat (map :block/original-name default-db/built-in-pages)
+                                                            ["page1" "page2"]))
+                                (sort (map :block/page-name (:blocks edn-output))))
+                          "Correct pages")))

+ 6 - 6
static/yarn.lock

@@ -1068,13 +1068,13 @@ base64-js@^1.3.1, base64-js@^1.5.1:
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
 
-better-sqlite3@8.0.1:
-  version "8.0.1"
-  resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-8.0.1.tgz#3a596d21fbcefadf36f94e126c5cf24d5697d0b8"
-  integrity sha512-JhTZjpyapA1icCEjIZB4TSSgkGdFgpWZA2Wszg7Cf4JwJwKQmbvuNnJBeR+EYG/Z29OXvR4G//Rbg31BW/Z7Yg==
+better-sqlite3@9.3.0:
+  version "9.3.0"
+  resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-9.3.0.tgz#2a8aaad65fa0210a4df5e8a0bcbc9156f6138d56"
+  integrity sha512-ww73jVpQhRRdS9uMr761ixlkl4bWoXi8hMQlBGhoN6vPNlUHpIsNmw4pKN6kjknlt/wopdvXHvLk1W75BI+n0Q==
   dependencies:
     bindings "^1.5.0"
-    prebuild-install "^7.1.0"
+    prebuild-install "^7.1.1"
 
 binary-extensions@^2.0.0:
   version "2.2.0"
@@ -4044,7 +4044,7 @@ [email protected]:
   dependencies:
     fflate "^0.4.1"
 
-prebuild-install@^7.1.0:
+prebuild-install@^7.1.1:
   version "7.1.1"
   resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45"
   integrity sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==