Просмотр исходного кода

Merge branch 'feat/db' into feat/capacitor-new

charlie 11 месяцев назад
Родитель
Сommit
bf040e07db
100 измененных файлов с 814 добавлено и 2078 удалено
  1. 3 2
      .clj-kondo/config.edn
  2. 1 1
      .github/workflows/build-android.yml
  3. 1 1
      .github/workflows/build-demo.yml
  4. 39 34
      .github/workflows/build-desktop-release.yml
  5. 1 1
      .github/workflows/build-ios-release.yml
  6. 1 1
      .github/workflows/build-ios.yml
  7. 1 1
      .github/workflows/build-stage.yml
  8. 1 1
      .github/workflows/build.yml
  9. 1 1
      .github/workflows/clj-e2e.yml
  10. 1 1
      .github/workflows/db.yml
  11. 1 1
      .github/workflows/deploy-db-test-pages.yml
  12. 1 1
      .github/workflows/e2e.yml
  13. 1 1
      .github/workflows/graph-parser.yml
  14. 1 1
      .github/workflows/logseq-common.yml
  15. 1 1
      .github/workflows/outliner.yml
  16. 1 1
      .github/workflows/publishing.yml
  17. 1 1
      bb.edn
  18. 1 1
      clj-e2e/deps.edn
  19. 1 1
      deps.edn
  20. 1 1
      deps/common/package.json
  21. 21 21
      deps/common/src/logseq/common/path.cljs
  22. 8 8
      deps/common/yarn.lock
  23. 2 2
      deps/db/deps.edn
  24. 2 2
      deps/db/package.json
  25. 2 2
      deps/db/src/logseq/db/common/view.cljs
  26. 41 22
      deps/db/src/logseq/db/sqlite/export.cljs
  27. 53 1
      deps/db/test/logseq/db/sqlite/export_test.cljs
  28. 12 12
      deps/db/yarn.lock
  29. 8 7
      deps/graph-parser/deps.edn
  30. 1 0
      deps/graph-parser/nbb.edn
  31. 2 2
      deps/graph-parser/package.json
  32. 22 7
      deps/graph-parser/src/logseq/graph_parser/exporter.cljs
  33. 2 2
      deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs
  34. 22 1
      deps/graph-parser/test/resources/exporter-test-graph/journals/2024_08_07.md
  35. 0 2
      deps/graph-parser/test/resources/exporter-test-graph/logseq/config.edn
  36. 12 12
      deps/graph-parser/yarn.lock
  37. 4 2
      deps/outliner/deps.edn
  38. 2 2
      deps/outliner/package.json
  39. 12 12
      deps/outliner/yarn.lock
  40. 2 2
      deps/publishing/package.json
  41. 12 12
      deps/publishing/yarn.lock
  42. 5 4
      package.json
  43. 1 1
      resources/forge.config.js
  44. 0 45
      resources/js/preload.js
  45. 15 15
      resources/package.json
  46. 2 2
      scripts/package.json
  47. 5 5
      scripts/src/logseq/tasks/lang.clj
  48. 12 12
      scripts/yarn.lock
  49. 1 1
      src/main/frontend/commands.cljs
  50. 2 4
      src/main/frontend/components/block.cljs
  51. 12 11
      src/main/frontend/components/block/macros.cljs
  52. 12 14
      src/main/frontend/components/container.cljs
  53. 1 1
      src/main/frontend/components/content.cljs
  54. 2 2
      src/main/frontend/components/file_sync.cljs
  55. 29 29
      src/main/frontend/components/file_sync.css
  56. 1 1
      src/main/frontend/components/imports.cljs
  57. 10 10
      src/main/frontend/components/plugins.cljs
  58. 2 1
      src/main/frontend/components/property/value.cljs
  59. 1 1
      src/main/frontend/components/query/builder.cljs
  60. 2 2
      src/main/frontend/components/repo.cljs
  61. 1 1
      src/main/frontend/components/right_sidebar.css
  62. 23 15
      src/main/frontend/components/rtc/indicator.cljs
  63. 3 3
      src/main/frontend/components/theme.cljs
  64. 31 21
      src/main/frontend/components/views.cljs
  65. 6 16
      src/main/frontend/db/persist.cljs
  66. 7 28
      src/main/frontend/encrypt.cljs
  67. 20 23
      src/main/frontend/extensions/excalidraw.cljs
  68. 6 5
      src/main/frontend/extensions/pdf/assets.cljs
  69. 1 1
      src/main/frontend/extensions/zotero/handler.cljs
  70. 1 2
      src/main/frontend/flows.cljs
  71. 14 41
      src/main/frontend/fs.cljs
  72. 0 404
      src/main/frontend/fs/capacitor_fs.cljs
  73. 0 366
      src/main/frontend/fs/nfs.cljs
  74. 74 300
      src/main/frontend/fs/sync.cljs
  75. 0 5
      src/main/frontend/handler.cljs
  76. 2 19
      src/main/frontend/handler/assets.cljs
  77. 2 1
      src/main/frontend/handler/db_based/rtc_flows.cljs
  78. 1 1
      src/main/frontend/handler/dnd.cljs
  79. 12 10
      src/main/frontend/handler/draw.cljs
  80. 17 36
      src/main/frontend/handler/editor.cljs
  81. 13 85
      src/main/frontend/handler/events.cljs
  82. 1 38
      src/main/frontend/handler/events/ui.cljs
  83. 22 48
      src/main/frontend/handler/file_based/editor.cljs
  84. 6 6
      src/main/frontend/handler/file_based/events.cljs
  85. 41 54
      src/main/frontend/handler/file_based/file.cljs
  86. 5 7
      src/main/frontend/handler/file_based/native_fs.cljs
  87. 15 51
      src/main/frontend/handler/file_based/repo.cljs
  88. 13 13
      src/main/frontend/handler/global_config.cljs
  89. 2 2
      src/main/frontend/handler/page.cljs
  90. 23 16
      src/main/frontend/handler/plugin.cljs
  91. 2 2
      src/main/frontend/handler/plugin_config.cljs
  92. 6 3
      src/main/frontend/handler/user.cljs
  93. 8 7
      src/main/frontend/idb.cljs
  94. 1 1
      src/main/frontend/mobile/action_bar.cljs
  95. 4 51
      src/main/frontend/mobile/core.cljs
  96. 1 1
      src/main/frontend/mobile/graph_picker.cljs
  97. 1 1
      src/main/frontend/mobile/intent.cljs
  98. 10 22
      src/main/frontend/mobile/util.cljs
  99. 2 9
      src/main/frontend/persist_db/browser.cljs
  100. 0 15
      src/main/frontend/state.cljs

+ 3 - 2
.clj-kondo/config.edn

@@ -59,6 +59,7 @@
   :consistent-alias
   :consistent-alias
   {:aliases {"/electron/utils" js-utils
   {:aliases {"/electron/utils" js-utils
              "path" node-path
              "path" node-path
+             borkdude.rewrite-edn rewrite
              cljs-time.coerce tc
              cljs-time.coerce tc
              cljs-time.core t
              cljs-time.core t
              cljs.reader reader
              cljs.reader reader
@@ -98,9 +99,7 @@
              frontend.format.block block
              frontend.format.block block
              frontend.format.mldoc mldoc
              frontend.format.mldoc mldoc
              frontend.fs fs
              frontend.fs fs
-             frontend.fs.capacitor-fs capacitor-fs
              frontend.fs.memory-fs memory-fs
              frontend.fs.memory-fs memory-fs
-             frontend.fs.nfs nfs
              frontend.handler.common common-handler
              frontend.handler.common common-handler
              frontend.handler.common.developer dev-common-handler
              frontend.handler.common.developer dev-common-handler
              frontend.handler.common.page page-common-handler
              frontend.handler.common.page page-common-handler
@@ -115,6 +114,7 @@
              frontend.handler.events events
              frontend.handler.events events
              frontend.handler.extract extract
              frontend.handler.extract extract
              frontend.handler.file-based.file file-handler
              frontend.handler.file-based.file file-handler
+             frontend.handler.file-based.native-fs nfs-handler
              frontend.handler.file-based.page file-page-handler
              frontend.handler.file-based.page file-page-handler
              frontend.handler.file-based.page-property file-page-property
              frontend.handler.file-based.page-property file-page-property
              frontend.handler.file-based.property file-property-handler
              frontend.handler.file-based.property file-property-handler
@@ -158,6 +158,7 @@
              frontend.util.text text-util
              frontend.util.text text-util
              frontend.util.thingatpt thingatpt
              frontend.util.thingatpt thingatpt
              frontend.util.url url-util
              frontend.util.url url-util
+             frontend.util.ref ref
              frontend.worker.shared-service shared-service
              frontend.worker.shared-service shared-service
              frontend.worker.handler.page worker-page
              frontend.worker.handler.page worker-page
              frontend.worker.pipeline worker-pipeline
              frontend.worker.pipeline worker-pipeline

+ 1 - 1
.github/workflows/build-android.yml

@@ -42,7 +42,7 @@ on:
 
 
 env:
 env:
   CLOJURE_VERSION: '1.11.1.1413'
   CLOJURE_VERSION: '1.11.1.1413'
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   JAVA_VERSION: '17'
   JAVA_VERSION: '17'
 
 
 jobs:
 jobs:

+ 1 - 1
.github/workflows/build-demo.yml

@@ -19,7 +19,7 @@ on:
 
 
 env:
 env:
   CLOJURE_VERSION: '1.11.1.1413'
   CLOJURE_VERSION: '1.11.1.1413'
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   JAVA_VERSION: '17'
   JAVA_VERSION: '17'
 
 
 jobs:
 jobs:

+ 39 - 34
.github/workflows/build-desktop-release.yml

@@ -38,17 +38,17 @@ on:
         type: boolean
         type: boolean
         required: true
         required: true
         default: true
         default: true
-      build-android:
-        description: 'Build Android App'
-        type: boolean
-        required: true
-        default: true
+      # build-android:
+      #   description: 'Build Android App'
+      #   type: boolean
+      #   required: true
+      #   default: true
   schedule: # Every workday at the 2 P.M. (UTC) we run a scheduled nightly build
   schedule: # Every workday at the 2 P.M. (UTC) we run a scheduled nightly build
     - cron: '0 14 * * MON-FRI'
     - cron: '0 14 * * MON-FRI'
 
 
 env:
 env:
   CLOJURE_VERSION: '1.11.1.1413'
   CLOJURE_VERSION: '1.11.1.1413'
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   JAVA_VERSION: '11'
   JAVA_VERSION: '11'
 
 
 jobs:
 jobs:
@@ -307,6 +307,8 @@ jobs:
       - name: Build/Release Electron app
       - name: Build/Release Electron app
         run: yarn electron:make
         run: yarn electron:make
         working-directory: ./static
         working-directory: ./static
+        env:
+          DEBUG: electron-packager
         #env:
         #env:
         #  CODE_SIGN_CERTIFICATE_FILE: ../codesign.pfx
         #  CODE_SIGN_CERTIFICATE_FILE: ../codesign.pfx
         #  CODE_SIGN_CERTIFICATE_PASSWORD: ${{ secrets.CODE_SIGN_CERTIFICATE_PASSWORD }}
         #  CODE_SIGN_CERTIFICATE_PASSWORD: ${{ secrets.CODE_SIGN_CERTIFICATE_PASSWORD }}
@@ -393,7 +395,7 @@ jobs:
       #     key: ${{ runner.os }}-node-modules
       #     key: ${{ runner.os }}-node-modules
 
 
       - name: Build/Release Electron App for x64
       - name: Build/Release Electron App for x64
-        run: yarn install && yarn electron:make
+        run: yarn install && yarn rebuild:all && yarn electron:make
         working-directory: ./static
         working-directory: ./static
         env:
         env:
           APPLE_ID: ${{ secrets.APPLE_ID_EMAIL }}
           APPLE_ID: ${{ secrets.APPLE_ID_EMAIL }}
@@ -466,7 +468,7 @@ jobs:
       #     key: ${{ runner.os }}-node-modules
       #     key: ${{ runner.os }}-node-modules
 
 
       - name: Fetch deps and fix dugit arch for arm64
       - name: Fetch deps and fix dugit arch for arm64
-        run: yarn install --ignore-platform && cd node_modules/dugite && npm_config_arch=arm64 node script/download-git.js
+        run: yarn install --ignore-platform && yarn rebuild:all && cd node_modules/dugite && npm_config_arch=arm64 node script/download-git.js
         working-directory: ./static
         working-directory: ./static
 
 
       - name: Build/Release Electron App for arm64
       - name: Build/Release Electron App for arm64
@@ -490,23 +492,26 @@ jobs:
           path: builds
           path: builds
 
 
   # reuse workflow via workflow_call
   # reuse workflow via workflow_call
-  build-android:
-    uses: ./.github/workflows/build-android.yml
-    if: ${{ github.event_name == 'schedule' || github.event.inputs.build-android == 'true' }}
-    with:
-      build-target: "${{ github.event.inputs.build-target }}"
-      # if scheduled, use production mode
-      enable-file-sync-production: "${{ github.event_name == 'schedule' || github.event.inputs.enable-file-sync-production == 'true' }}"
-    secrets:
-      ANDROID_KEYSTORE: "${{ secrets.ANDROID_KEYSTORE }}"
-      ANDROID_KEYSTORE_PASSWORD: "${{ secrets.ANDROID_KEYSTORE_PASSWORD }}"
-      SENTRY_AUTH_TOKEN: "${{ secrets.SENTRY_AUTH_TOKEN }}"
+  # build-android:
+  #   uses: ./.github/workflows/build-android.yml
+  #   if: ${{ github.event_name == 'schedule' || github.event.inputs.build-android == 'true' }}
+  #   with:
+  #     build-target: "${{ github.event.inputs.build-target }}"
+  #     # if scheduled, use production mode
+  #     enable-file-sync-production: "${{ github.event_name == 'schedule' || github.event.inputs.enable-file-sync-production == 'true' }}"
+  #   secrets:
+  #     ANDROID_KEYSTORE: "${{ secrets.ANDROID_KEYSTORE }}"
+  #     ANDROID_KEYSTORE_PASSWORD: "${{ secrets.ANDROID_KEYSTORE_PASSWORD }}"
+  #     SENTRY_AUTH_TOKEN: "${{ secrets.SENTRY_AUTH_TOKEN }}"
 
 
   codesign-windows:
   codesign-windows:
     if: ${{ github.event_name == 'schedule' || github.event.inputs.build-target == 'nightly' || github.event.inputs.build-target == 'beta' }}
     if: ${{ github.event_name == 'schedule' || github.event.inputs.build-target == 'nightly' || github.event.inputs.build-target == 'beta' }}
     needs: [ build-windows ]
     needs: [ build-windows ]
     runs-on: [self-hosted, macos, token]
     runs-on: [self-hosted, macos, token]
     steps:
     steps:
+      - name: Remove old builds
+        run: rm -rf ./builds && mkdir ./builds
+
       - name: Download Windows Artifact
       - name: Download Windows Artifact
         uses: actions/download-artifact@v4
         uses: actions/download-artifact@v4
         with:
         with:
@@ -528,7 +533,7 @@ jobs:
 
 
   nightly-release:
   nightly-release:
     if: ${{ github.event_name == 'schedule' || github.event.inputs.build-target == 'nightly' }}
     if: ${{ github.event_name == 'schedule' || github.event.inputs.build-target == 'nightly' }}
-    needs: [ build-macos-x64, build-macos-arm64, build-linux-x64, build-linux-arm64, codesign-windows, build-android]
+    needs: [ build-macos-x64, build-macos-arm64, build-linux-x64, build-linux-arm64, codesign-windows]
     runs-on: ubuntu-22.04
     runs-on: ubuntu-22.04
     steps:
     steps:
       - name: Download MacOS x64 Artifacts
       - name: Download MacOS x64 Artifacts
@@ -567,11 +572,11 @@ jobs:
           name: logseq-win64-builds
           name: logseq-win64-builds
           path: ./
           path: ./
 
 
-      - name: Download Android Artifacts
-        uses: actions/download-artifact@v4
-        with:
-          name: logseq-android-builds
-          path: ./
+      # - name: Download Android Artifacts
+      #   uses: actions/download-artifact@v4
+      #   with:
+      #     name: logseq-android-builds
+      #     path: ./
 
 
       - name: Generate SHA256 checksums
       - name: Generate SHA256 checksums
         run: |
         run: |
@@ -590,7 +595,7 @@ jobs:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
         with:
           tag_name: nightly
           tag_name: nightly
-          name: 'Desktop/Android APP Nightly Release $$'
+          name: 'Desktop app Nightly Release $$'
           draft: false
           draft: false
           prerelease: ${{ (github.event_name == 'workflow_dispatch' && github.event.inputs.is-pre-release) || (github.event_name == 'schedule')}}
           prerelease: ${{ (github.event_name == 'workflow_dispatch' && github.event.inputs.is-pre-release) || (github.event_name == 'schedule')}}
           body: |
           body: |
@@ -608,7 +613,7 @@ jobs:
   release:
   release:
     # NOTE: For now, we only have beta channel to be released on Github
     # NOTE: For now, we only have beta channel to be released on Github
     if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.build-target == 'beta' }}
     if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.build-target == 'beta' }}
-    needs: [ build-macos-x64, build-macos-arm64, build-linux-x64, build-linux-arm64, codesign-windows, build-android]
+    needs: [ build-macos-x64, build-macos-arm64, build-linux-x64, build-linux-arm64, codesign-windows]
     runs-on: ubuntu-22.04
     runs-on: ubuntu-22.04
     steps:
     steps:
       - name: Download MacOS x64 Artifacts
       - name: Download MacOS x64 Artifacts
@@ -647,12 +652,12 @@ jobs:
           name: logseq-win64-builds
           name: logseq-win64-builds
           path: ./
           path: ./
 
 
-      - name: Download Android Artifacts
-        uses: actions/download-artifact@v4
-        if: ${{ github.event_name == 'schedule' || github.event.inputs.build-android == 'true' }}
-        with:
-          name: logseq-android-builds
-          path: ./
+      # - name: Download Android Artifacts
+      #   uses: actions/download-artifact@v4
+      #   if: ${{ github.event_name == 'schedule' || github.event.inputs.build-android == 'true' }}
+      #   with:
+      #     name: logseq-android-builds
+      #     path: ./
 
 
       - name: List files
       - name: List files
         run: ls -rl
         run: ls -rl
@@ -682,7 +687,7 @@ jobs:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
         with:
           tag_name: ${{ steps.ref.outputs.version }}
           tag_name: ${{ steps.ref.outputs.version }}
-          name: Desktop/Android APP ${{ steps.ref.outputs.version }} (Beta Testing)
+          name: Desktop APP ${{ steps.ref.outputs.version }} (Beta Testing)
           body: "TODO: Fill this changelog. Sorry for the inconvenience!"
           body: "TODO: Fill this changelog. Sorry for the inconvenience!"
           draft: ${{ github.event.inputs.is-draft }}
           draft: ${{ github.event.inputs.is-draft }}
           prerelease: ${{ github.event.inputs.is-pre-release }}
           prerelease: ${{ github.event.inputs.is-pre-release }}

+ 1 - 1
.github/workflows/build-ios-release.yml

@@ -12,7 +12,7 @@ on:
 
 
 env:
 env:
   CLOJURE_VERSION: '1.11.1.1413'
   CLOJURE_VERSION: '1.11.1.1413'
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   JAVA_VERSION: '11'
   JAVA_VERSION: '11'
 
 
 jobs:
 jobs:

+ 1 - 1
.github/workflows/build-ios.yml

@@ -17,7 +17,7 @@ on:
 
 
 env:
 env:
   CLOJURE_VERSION: '1.11.1.1413'
   CLOJURE_VERSION: '1.11.1.1413'
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   JAVA_VERSION: '11'
   JAVA_VERSION: '11'
 
 
 jobs:
 jobs:

+ 1 - 1
.github/workflows/build-stage.yml

@@ -19,7 +19,7 @@ on:
 
 
 env:
 env:
   CLOJURE_VERSION: '1.11.1.1413'
   CLOJURE_VERSION: '1.11.1.1413'
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   JAVA_VERSION: '17'
   JAVA_VERSION: '17'
 
 
 jobs:
 jobs:

+ 1 - 1
.github/workflows/build.yml

@@ -14,7 +14,7 @@ env:
   CLOJURE_VERSION: '1.11.1.1413'
   CLOJURE_VERSION: '1.11.1.1413'
   JAVA_VERSION: '11'
   JAVA_VERSION: '11'
   # This is the latest node version we can run.
   # This is the latest node version we can run.
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   BABASHKA_VERSION: '1.0.168'
   BABASHKA_VERSION: '1.0.168'
 
 
 jobs:
 jobs:

+ 1 - 1
.github/workflows/clj-e2e.yml

@@ -21,7 +21,7 @@ on:
 env:
 env:
   CLOJURE_VERSION: '1.11.1.1413'
   CLOJURE_VERSION: '1.11.1.1413'
   # This is the latest node version we can run.
   # This is the latest node version we can run.
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   BABASHKA_VERSION: '1.0.168'
   BABASHKA_VERSION: '1.0.168'
 
 
 jobs:
 jobs:

+ 1 - 1
.github/workflows/db.yml

@@ -23,7 +23,7 @@ env:
   CLOJURE_VERSION: '1.11.1.1413'
   CLOJURE_VERSION: '1.11.1.1413'
   JAVA_VERSION: '11'
   JAVA_VERSION: '11'
   # This is the latest node version we can run.
   # This is the latest node version we can run.
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   BABASHKA_VERSION: '1.0.168'
   BABASHKA_VERSION: '1.0.168'
 
 
 jobs:
 jobs:

+ 1 - 1
.github/workflows/deploy-db-test-pages.yml

@@ -6,7 +6,7 @@ on:
 
 
 env:
 env:
   CLOJURE_VERSION: "1.11.1.1413"
   CLOJURE_VERSION: "1.11.1.1413"
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   JAVA_VERSION: "11"
   JAVA_VERSION: "11"
 
 
 jobs:
 jobs:

+ 1 - 1
.github/workflows/e2e.yml

@@ -19,7 +19,7 @@ env:
   CLOJURE_VERSION: '1.11.1.1413'
   CLOJURE_VERSION: '1.11.1.1413'
   JAVA_VERSION: '11'
   JAVA_VERSION: '11'
   # This is the latest node version we can run.
   # This is the latest node version we can run.
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   BABASHKA_VERSION: '1.0.168'
   BABASHKA_VERSION: '1.0.168'
 
 
 jobs:
 jobs:

+ 1 - 1
.github/workflows/graph-parser.yml

@@ -28,7 +28,7 @@ env:
   # This is the same as 1.8.
   # This is the same as 1.8.
   JAVA_VERSION: '11'
   JAVA_VERSION: '11'
   # This is the latest node version we can run.
   # This is the latest node version we can run.
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   BABASHKA_VERSION: '1.0.168'
   BABASHKA_VERSION: '1.0.168'
 
 
 jobs:
 jobs:

+ 1 - 1
.github/workflows/logseq-common.yml

@@ -23,7 +23,7 @@ env:
   CLOJURE_VERSION: '1.11.1.1413'
   CLOJURE_VERSION: '1.11.1.1413'
   JAVA_VERSION: '11'
   JAVA_VERSION: '11'
   # This is the latest node version we can run.
   # This is the latest node version we can run.
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   BABASHKA_VERSION: '1.0.168'
   BABASHKA_VERSION: '1.0.168'
 
 
 jobs:
 jobs:

+ 1 - 1
.github/workflows/outliner.yml

@@ -28,7 +28,7 @@ env:
   # This is the same as 1.8.
   # This is the same as 1.8.
   JAVA_VERSION: '11'
   JAVA_VERSION: '11'
   # This is the latest node version we can run.
   # This is the latest node version we can run.
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   BABASHKA_VERSION: '1.0.168'
   BABASHKA_VERSION: '1.0.168'
 
 
 jobs:
 jobs:

+ 1 - 1
.github/workflows/publishing.yml

@@ -28,7 +28,7 @@ env:
   # This is the same as 1.8.
   # This is the same as 1.8.
   JAVA_VERSION: '11'
   JAVA_VERSION: '11'
   # This is the latest node version we can run.
   # This is the latest node version we can run.
-  NODE_VERSION: '20'
+  NODE_VERSION: '22'
   BABASHKA_VERSION: '1.0.168'
   BABASHKA_VERSION: '1.0.168'
 
 
 jobs:
 jobs:

+ 1 - 1
bb.edn

@@ -2,7 +2,7 @@
  :deps
  :deps
  {metosin/malli
  {metosin/malli
   {:mvn/version "0.16.1"}
   {:mvn/version "0.16.1"}
-  borkdude/rewrite-edn {:mvn/version "0.4.8"}
+  borkdude/rewrite-edn {:mvn/version "0.4.9"}
   logseq/bb-tasks
   logseq/bb-tasks
   #_{:local/root "../bb-tasks"}
   #_{:local/root "../bb-tasks"}
   {:git/url "https://github.com/logseq/bb-tasks"
   {:git/url "https://github.com/logseq/bb-tasks"

+ 1 - 1
clj-e2e/deps.edn

@@ -2,7 +2,7 @@
  :deps {org.clojure/clojure {:mvn/version "1.12.0"}
  :deps {org.clojure/clojure {:mvn/version "1.12.0"}
         ;; io.github.pfeodrippe/wally {:local/root "../../../wally"}
         ;; io.github.pfeodrippe/wally {:local/root "../../../wally"}
         io.github.pfeodrippe/wally {:git/url "https://github.com/logseq/wally"
         io.github.pfeodrippe/wally {:git/url "https://github.com/logseq/wally"
-                                    :sha "d84a2e068ec2e56fc7028fc61e694ccd1ddea03b"}
+                                    :sha "8571fae7c51400ac61c8b1026cbfba68279bc461"}
         ;; io.github.zmedelis/bosquet {:mvn/version "2025.03.28"}
         ;; io.github.zmedelis/bosquet {:mvn/version "2025.03.28"}
         org.clj-commons/claypoole          {:mvn/version "1.2.2"}
         org.clj-commons/claypoole          {:mvn/version "1.2.2"}
         clj-time/clj-time                  {:mvn/version "0.15.2"}}
         clj-time/clj-time                  {:mvn/version "0.15.2"}}

+ 1 - 1
deps.edn

@@ -8,7 +8,7 @@
                                          :sha     "4b1f15f05a6b4a718a62c247956206480e361ea6"}
                                          :sha     "4b1f15f05a6b4a718a62c247956206480e361ea6"}
 
 
   datascript-transit/datascript-transit {:mvn/version "0.3.0"}
   datascript-transit/datascript-transit {:mvn/version "0.3.0"}
-  borkdude/rewrite-edn                  {:mvn/version "0.4.7"}
+  borkdude/rewrite-edn                  {:mvn/version "0.4.9"}
   funcool/promesa                       {:mvn/version "11.0.678"}
   funcool/promesa                       {:mvn/version "11.0.678"}
   medley/medley                         {:mvn/version "1.4.0"}
   medley/medley                         {:mvn/version "1.4.0"}
   metosin/reitit-frontend               {:mvn/version "0.3.10"}
   metosin/reitit-frontend               {:mvn/version "0.3.10"}

+ 1 - 1
deps/common/package.json

@@ -3,7 +3,7 @@
   "version": "1.0.0",
   "version": "1.0.0",
   "private": true,
   "private": true,
   "devDependencies": {
   "devDependencies": {
-    "@logseq/nbb-logseq": "logseq/nbb-logseq#feat-db-v20"
+    "@logseq/nbb-logseq": "logseq/nbb-logseq#feat-db-v23"
   },
   },
   "scripts": {
   "scripts": {
     "test": "yarn nbb-logseq -cp test -m nextjournal.test-runner"
     "test": "yarn nbb-logseq -cp test -m nextjournal.test-runner"

+ 21 - 21
deps/common/src/logseq/common/path.cljs

@@ -14,12 +14,11 @@
 (defn is-file-url?
 (defn is-file-url?
   [s]
   [s]
   (and (string? s)
   (and (string? s)
-       (or (string/starts-with? s "file://") ;; mobile platform
-           (string/starts-with? s "content://") ;; android only
-           (string/starts-with? s "assets://") ;; Electron asset, urlencoded
-           (string/starts-with? s "logseq://") ;; reserved for future fs protocol
-           (string/starts-with? s "memory://") ;; special memory fs
-           (string/starts-with? s "s3://"))))
+       (or
+        (string/starts-with? s "memory://") ;; special memory fs
+        (string/starts-with? s "assets://") ;; Electron asset, urlencoded
+        (string/starts-with? s "file://") ;; Electron files
+        )))
 
 
 (defn filename
 (defn filename
   "File name of a path or URL.
   "File name of a path or URL.
@@ -63,7 +62,6 @@
                 (re-find #"(?i)^(COM[0-9]|CON|LPT[0-9]|NUL|PRN|AUX|com[0-9]|con|lpt[0-9]|nul|prn|aux)\..+" fname)
                 (re-find #"(?i)^(COM[0-9]|CON|LPT[0-9]|NUL|PRN|AUX|com[0-9]|con|lpt[0-9]|nul|prn|aux)\..+" fname)
                 (re-find #"[\u0000-\u001f\u0080-\u009f]" fname)))))
                 (re-find #"[\u0000-\u001f\u0080-\u009f]" fname)))))
 
 
-
 (defn- path-join-internal
 (defn- path-join-internal
   "Joins the given path segments into a single path, handling relative paths,
   "Joins the given path segments into a single path, handling relative paths,
   '..' and '.' normalization."
   '..' and '.' normalization."
@@ -144,16 +142,16 @@
          (join-fn))))
          (join-fn))))
 
 
 (defn url-join
 (defn url-join
-  "Segments are not URL-ecoded"
+  "Segments are not URL-encoded"
   [base-url & segments]
   [base-url & segments]
-  (let [^js url (js/URL. base-url)
+  (let [^js url (js/URL. (safe-decode-uri-component base-url))
         scheme (.-protocol url)
         scheme (.-protocol url)
-        domain (or (not-empty (.-host url)) "")
-        path (safe-decode-uri-component (.-pathname url))
+        path (.-pathname url)
+        domain (or (not-empty (.-host url))
+                 (if (string/starts-with? path "/") "" "/"))
         encoded-new-path (apply uri-path-join-internal path segments)]
         encoded-new-path (apply uri-path-join-internal path segments)]
     (str scheme "//" domain encoded-new-path)))
     (str scheme "//" domain encoded-new-path)))
 
 
-
 (defn path-join
 (defn path-join
   "Join path segments, or URL base and path segments"
   "Join path segments, or URL base and path segments"
   [base & segments]
   [base & segments]
@@ -191,19 +189,17 @@
     :else
     :else
     (path-join (str protocol "//") path)))
     (path-join (str protocol "//") path)))
 
 
-
 (defn- path-normalize-internal
 (defn- path-normalize-internal
   "Normalize path using path-join, break into segment and re-join"
   "Normalize path using path-join, break into segment and re-join"
   [path]
   [path]
   (path-join path))
   (path-join path))
 
 
-
 (defn url-normalize
 (defn url-normalize
   [origin-url]
   [origin-url]
-  (let [^js url (js/URL. origin-url)
+  (let [^js url (js/URL. (safe-decode-uri-component origin-url))
         scheme (.-protocol url)
         scheme (.-protocol url)
-        domain (or (not-empty (.-host url)) "")
-        path (safe-decode-uri-component (.-pathname url))
+        domain (or (not-empty (.-host url)) "/")
+        path (.-pathname url)
         encoded-new-path (uri-path-join-internal path)]
         encoded-new-path (uri-path-join-internal path)]
     (str scheme "//" domain encoded-new-path)))
     (str scheme "//" domain encoded-new-path)))
 
 
@@ -223,8 +219,14 @@
   (if (is-file-url? original-url)
   (if (is-file-url? original-url)
     ;; NOTE: URL type is not consistent across all protocols
     ;; NOTE: URL type is not consistent across all protocols
     ;; Check file:// and assets://, pathname behavior is different
     ;; Check file:// and assets://, pathname behavior is different
-    (let [^js url (js/URL. (string/replace original-url "assets://" "file://"))
-          path (safe-decode-uri-component (.-pathname url))
+    (let [^js url (try
+                    (js/URL. (string/replace (safe-decode-uri-component original-url) "assets://" "file://"))
+                    (catch :default e
+                      (js/console.error "invalid URL:"
+                                        (str "original-url: " original-url
+                                             " url: " (string/replace (safe-decode-uri-component original-url) "assets://" "file://")))
+                      (throw e)))
+          path (.-pathname url)
           host (.-host url)
           host (.-host url)
           path (if (string/starts-with? path "///")
           path (if (string/starts-with? path "///")
                  (subs path 2)
                  (subs path 2)
@@ -276,7 +278,6 @@
           (safe-decode-uri-component (str base-prefix (string/join "/" remain-segs)))
           (safe-decode-uri-component (str base-prefix (string/join "/" remain-segs)))
           (str base-prefix (string/join "/" remain-segs)))))))
           (str base-prefix (string/join "/" remain-segs)))))))
 
 
-
 (defn parent
 (defn parent
   "Parent, containing directory"
   "Parent, containing directory"
   [path]
   [path]
@@ -285,7 +286,6 @@
     (path-normalize (str path "/.."))
     (path-normalize (str path "/.."))
     nil))
     nil))
 
 
-
 (defn resolve-relative-path
 (defn resolve-relative-path
   "Assume current-path is a file"
   "Assume current-path is a file"
   [current-path rel-path]
   [current-path rel-path]

+ 8 - 8
deps/common/yarn.lock

@@ -2,13 +2,13 @@
 # yarn lockfile v1
 # yarn lockfile v1
 
 
 
 
-"@logseq/nbb-logseq@logseq/nbb-logseq#feat-db-v20":
-  version "1.2.173-feat-db-v20"
-  resolved "https://codeload.github.com/logseq/nbb-logseq/tar.gz/7fb63423ab566717cac79e5f76084d89b845fbd6"
+"@logseq/nbb-logseq@logseq/nbb-logseq#feat-db-v23":
+  version "1.2.173-feat-db-v23"
+  resolved "https://codeload.github.com/logseq/nbb-logseq/tar.gz/810782c4ddba6346c4ab8ae6740b60438c07cd01"
   dependencies:
   dependencies:
-    import-meta-resolve "^2.1.0"
+    import-meta-resolve "^4.1.0"
 
 
-import-meta-resolve@^2.1.0:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-2.2.2.tgz#75237301e72d1f0fbd74dbc6cca9324b164c2cc9"
-  integrity sha512-f8KcQ1D80V7RnqVm+/lirO9zkOxjGxhaTC1IPrBGd3MEfNgmNG67tSUO9gTi2F3Blr2Az6g1vocaxzkVnWl9MA==
+import-meta-resolve@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#f9db8bead9fafa61adb811db77a2bf22c5399706"
+  integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==

+ 2 - 2
deps/db/deps.edn

@@ -1,5 +1,5 @@
 {:deps
 {:deps
- ;; These deps are kept in sync with https://github.com/logseq/nbb-logseq/blob/main/bb.edn
+ ;; These nbb-logseq deps are kept in sync with https://github.com/logseq/nbb-logseq/blob/main/bb.edn
  {datascript/datascript {:git/url "https://github.com/logseq/datascript" ;; fork
  {datascript/datascript {:git/url "https://github.com/logseq/datascript" ;; fork
                          :sha     "4b1f15f05a6b4a718a62c247956206480e361ea6"}
                          :sha     "4b1f15f05a6b4a718a62c247956206480e361ea6"}
   datascript-transit/datascript-transit {:mvn/version "0.3.0"
   datascript-transit/datascript-transit {:mvn/version "0.3.0"
@@ -8,7 +8,7 @@
   com.cognitect/transit-cljs   {:mvn/version "0.8.280"}
   com.cognitect/transit-cljs   {:mvn/version "0.8.280"}
   org.flatland/ordered         {:mvn/version "1.15.11"}
   org.flatland/ordered         {:mvn/version "1.15.11"}
 
 
-  ;; New deps should be added here and to nbb.edn
+  ;; Any other deps should be added here and to nbb.edn
   logseq/common                {:local/root "../common"}
   logseq/common                {:local/root "../common"}
   logseq/clj-fractional-indexing        {:git/url "https://github.com/logseq/clj-fractional-indexing"
   logseq/clj-fractional-indexing        {:git/url "https://github.com/logseq/clj-fractional-indexing"
                                          :sha     "7182b7878410f78536dc2b6df35ed32ef9cd6b61"}
                                          :sha     "7182b7878410f78536dc2b6df35ed32ef9cd6b61"}

+ 2 - 2
deps/db/package.json

@@ -3,10 +3,10 @@
   "version": "1.0.0",
   "version": "1.0.0",
   "private": true,
   "private": true,
   "devDependencies": {
   "devDependencies": {
-    "@logseq/nbb-logseq": "logseq/nbb-logseq#feat-db-v20"
+    "@logseq/nbb-logseq": "logseq/nbb-logseq#feat-db-v23"
   },
   },
   "dependencies": {
   "dependencies": {
-    "better-sqlite3": "9.3.0"
+    "better-sqlite3": "11.10.0"
   },
   },
   "scripts": {
   "scripts": {
     "test": "yarn nbb-logseq -cp test -m nextjournal.test-runner",
     "test": "yarn nbb-logseq -cp test -m nextjournal.test-runner",

+ 2 - 2
deps/db/src/logseq/db/common/view.cljs

@@ -506,7 +506,7 @@
      (common-util/distinct-by :label))))
      (common-util/distinct-by :label))))
 
 
 (defn ^:api ^:large-vars/cleanup-todo get-view-data
 (defn ^:api ^:large-vars/cleanup-todo get-view-data
-  [db view-id {:keys [journals? _view-for-id view-feature-type input query-entity-ids filters sorting]
+  [db view-id {:keys [journals? _view-for-id view-feature-type group-by-property-ident input query-entity-ids filters sorting]
                :as opts}]
                :as opts}]
   ;; TODO: create a view for journals maybe?
   ;; TODO: create a view for journals maybe?
   (cond
   (cond
@@ -519,7 +519,7 @@
     (let [view (d/entity db view-id)
     (let [view (d/entity db view-id)
           group-by-property (:logseq.property.view/group-by-property view)
           group-by-property (:logseq.property.view/group-by-property view)
           list-view? (= :logseq.property.view/type.list (:db/ident (:logseq.property.view/type view)))
           list-view? (= :logseq.property.view/type.list (:db/ident (:logseq.property.view/type view)))
-          group-by-property-ident (:db/ident group-by-property)
+          group-by-property-ident (or (:db/ident group-by-property) group-by-property-ident)
           group-by-closed-values? (some? (:property/closed-values group-by-property))
           group-by-closed-values? (some? (:property/closed-values group-by-property))
           ref-property? (= (:db/valueType group-by-property) :db.type/ref)
           ref-property? (= (:db/valueType group-by-property) :db.type/ref)
           filters (or (:logseq.property.table/filters view) filters)
           filters (or (:logseq.property.table/filters view) filters)

+ 41 - 22
deps/db/src/logseq/db/sqlite/export.cljs

@@ -847,29 +847,52 @@
 ;; Import fns
 ;; Import fns
 ;; ==========
 ;; ==========
 (defn- add-uuid-to-page-if-exists
 (defn- add-uuid-to-page-if-exists
-  [db m]
+  [db import-to-existing-page-uuids m]
   (if-let [ent (some->> (:build/journal m)
   (if-let [ent (some->> (:build/journal m)
                         (d/datoms db :avet :block/journal-day)
                         (d/datoms db :avet :block/journal-day)
                         first
                         first
                         :e
                         :e
                         (d/entity db))]
                         (d/entity db))]
-    (assoc m :block/uuid (:block/uuid ent))
+    (do
+      (swap! import-to-existing-page-uuids assoc (:block/uuid m) (:block/uuid ent))
+      (assoc m :block/uuid (:block/uuid ent)))
     ;; TODO: For now only check page uniqueness by title. Could handle more uniqueness checks later
     ;; TODO: For now only check page uniqueness by title. Could handle more uniqueness checks later
     (if-let [ent (some->> (:block/title m) (ldb/get-case-page db))]
     (if-let [ent (some->> (:block/title m) (ldb/get-case-page db))]
-      (assoc m :block/uuid (:block/uuid ent))
+      (do
+        (swap! import-to-existing-page-uuids assoc (:block/uuid m) (:block/uuid ent))
+        (assoc m :block/uuid (:block/uuid ent)))
       m)))
       m)))
 
 
+(defn- update-existing-properties
+  "Updates existing properties by ident. Also check imported and existing properties have
+   the same cardinality and type to avoid failure after import"
+  [db property-conflicts properties]
+  (->> properties
+       (map (fn [[k v]]
+              (if-let [ent (d/entity db k)]
+                (do
+                  (when (not= (select-keys ent [:logseq.property/type :db/cardinality])
+                              (select-keys v [:logseq.property/type :db/cardinality]))
+                    (swap! property-conflicts conj
+                           {:property-id k
+                            :actual (select-keys v [:logseq.property/type :db/cardinality])
+                            :expected (select-keys ent [:logseq.property/type :db/cardinality])}))
+                  [k (assoc v :block/uuid (:block/uuid ent))])
+                [k v])))
+       (into {})))
+
 (defn- check-for-existing-entities
 (defn- check-for-existing-entities
   "Checks export map for existing entities and adds :block/uuid to them if they exist in graph to import.
   "Checks export map for existing entities and adds :block/uuid to them if they exist in graph to import.
    Also checks for property conflicts between existing properties and properties to be imported"
    Also checks for property conflicts between existing properties and properties to be imported"
   [db {:keys [pages-and-blocks classes properties] ::keys [export-type] :as export-map} property-conflicts]
   [db {:keys [pages-and-blocks classes properties] ::keys [export-type] :as export-map} property-conflicts]
-  (let [export-map
+  (let [import-to-existing-page-uuids (atom {})
+        export-map
         (cond-> {:build-existing-tx? true
         (cond-> {:build-existing-tx? true
                  :extract-content-refs? false}
                  :extract-content-refs? false}
           (seq pages-and-blocks)
           (seq pages-and-blocks)
           (assoc :pages-and-blocks
           (assoc :pages-and-blocks
                  (mapv (fn [m]
                  (mapv (fn [m]
-                         (update m :page (partial add-uuid-to-page-if-exists db)))
+                         (update m :page (partial add-uuid-to-page-if-exists db import-to-existing-page-uuids)))
                        pages-and-blocks))
                        pages-and-blocks))
           (seq classes)
           (seq classes)
           (assoc :classes
           (assoc :classes
@@ -880,20 +903,7 @@
                                [k v])))
                                [k v])))
                       (into {})))
                       (into {})))
           (seq properties)
           (seq properties)
-          (assoc :properties
-                 (->> properties
-                      (map (fn [[k v]]
-                             (if-let [ent (d/entity db k)]
-                               (do
-                                 (when (not= (select-keys ent [:logseq.property/type :db/cardinality])
-                                             (select-keys v [:logseq.property/type :db/cardinality]))
-                                   (swap! property-conflicts conj
-                                          {:property-id k
-                                           :actual (select-keys v [:logseq.property/type :db/cardinality])
-                                           :expected (select-keys ent [:logseq.property/type :db/cardinality])}))
-                                 [k (assoc v :block/uuid (:block/uuid ent))])
-                               [k v])))
-                      (into {})))
+          (assoc :properties (update-existing-properties db property-conflicts properties))
           ;; Graph export doesn't use :build/page so this speeds up build
           ;; Graph export doesn't use :build/page so this speeds up build
           (= :graph export-type)
           (= :graph export-type)
           (assoc :translate-property-values? false)
           (assoc :translate-property-values? false)
@@ -904,10 +914,19 @@
                       export-map
                       export-map
                       (walk/postwalk (fn [f]
                       (walk/postwalk (fn [f]
                                        (if (and (vector? f) (= :build/page (first f)))
                                        (if (and (vector? f) (= :build/page (first f)))
-                                         [:build/page (add-uuid-to-page-if-exists db (second f))]
+                                         [:build/page
+                                          (add-uuid-to-page-if-exists db import-to-existing-page-uuids (second f))]
                                          f))
                                          f))
-                                     export-map))]
-    export-map'))
+                                     export-map))
+        ;; Update uuid references of all pages that had their uuids updated to reference an existing page
+        export-map''
+        (walk/postwalk (fn [f]
+                         (if-let [new-uuid (and (vector? f) (= :block/uuid (first f))
+                                                (get @import-to-existing-page-uuids (second f)))]
+                           [:block/uuid new-uuid]
+                           f))
+                       export-map')]
+    export-map''))
 
 
 (defn- build-block-import-options
 (defn- build-block-import-options
   "Builds options for sqlite-build to import into current-block"
   "Builds options for sqlite-build to import into current-block"

+ 53 - 1
deps/db/test/logseq/db/sqlite/export_test.cljs

@@ -824,4 +824,56 @@
     (is (= (expand-properties (:properties original-data)) (:properties imported-graph)))
     (is (= (expand-properties (:properties original-data)) (:properties imported-graph)))
     (is (= (expand-classes (:classes original-data))
     (is (= (expand-classes (:classes original-data))
            (-> (:classes imported-graph)
            (-> (:classes imported-graph)
-               (medley/dissoc-in [:user.property/p1 :build/properties]))))))
+               (medley/dissoc-in [:user.property/p1 :build/properties]))))))
+
+(deftest build-import-can-import-existing-page-with-different-uuid
+  (let [original-data
+        {:properties {:user.property/node {:logseq.property/type :node
+                                           :db/cardinality :db.cardinality/many}}
+         :pages-and-blocks
+         [{:page {:block/title "page1"
+                  :build/properties {:user.property/node #{[:build/page {:block/title "node1"}]}}}}]}
+        conn (db-test/create-conn-with-blocks original-data)
+        page-uuid (:block/uuid (db-test/find-page-by-title @conn "node1"))
+        _ (validate-db @conn)
+        ;; This is just a temp uuid used to link to the page during import
+        temp-uuid (random-uuid)
+        existing-data
+        {:properties {:user.property/node {:logseq.property/type :node
+                                           :db/cardinality :db.cardinality/many}}
+         :pages-and-blocks
+         [{:page {:block/title "node1"
+                  :block/uuid temp-uuid
+                  :build/keep-uuid? true}}
+          {:page {:block/title "page2"
+                  :build/properties {:user.property/node #{[:block/uuid temp-uuid]}}}}]}
+        {:keys [init-tx block-props-tx] :as _txs}
+        (sqlite-export/build-import existing-data @conn {})
+        ;; _ (cljs.pprint/pprint _txs)
+        _ (d/transact! conn init-tx)
+        _ (d/transact! conn block-props-tx)
+        _ (validate-db @conn)
+        expected-pages-and-blocks
+        [{:page
+          {:block/uuid page-uuid
+           :build/keep-uuid? true,
+           :block/title "node1"},
+          :blocks []}
+         {:page
+          {:build/properties
+           {:user.property/node
+            #{[:block/uuid page-uuid]}},
+           :block/title "page1"},
+          :blocks []}
+         {:page
+          {:build/properties
+           {:user.property/node
+            #{[:block/uuid page-uuid]}},
+           :block/title "page2"},
+          :blocks []}],
+        exported-graph (sqlite-export/build-export @conn {:export-type :graph
+                                                          :graph-options {:exclude-built-in-pages? true}})]
+    (is (= expected-pages-and-blocks
+           (:pages-and-blocks exported-graph))
+        "page uuid ('node1') is preserved across imports even when its assigned a temporary
+         uuid to relate it to other nodes")))

+ 12 - 12
deps/db/yarn.lock

@@ -2,21 +2,21 @@
 # yarn lockfile v1
 # yarn lockfile v1
 
 
 
 
-"@logseq/nbb-logseq@logseq/nbb-logseq#feat-db-v20":
-  version "1.2.173-feat-db-v20"
-  resolved "https://codeload.github.com/logseq/nbb-logseq/tar.gz/7fb63423ab566717cac79e5f76084d89b845fbd6"
+"@logseq/nbb-logseq@logseq/nbb-logseq#feat-db-v23":
+  version "1.2.173-feat-db-v23"
+  resolved "https://codeload.github.com/logseq/nbb-logseq/tar.gz/810782c4ddba6346c4ab8ae6740b60438c07cd01"
   dependencies:
   dependencies:
-    import-meta-resolve "^2.1.0"
+    import-meta-resolve "^4.1.0"
 
 
 base64-js@^1.3.1:
 base64-js@^1.3.1:
   version "1.5.1"
   version "1.5.1"
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
   integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
 
 
-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==
+better-sqlite3@11.10.0:
+  version "11.10.0"
+  resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.10.0.tgz#2b1b14c5acd75a43fd84d12cc291ea98cef57d98"
+  integrity sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==
   dependencies:
   dependencies:
     bindings "^1.5.0"
     bindings "^1.5.0"
     prebuild-install "^7.1.1"
     prebuild-install "^7.1.1"
@@ -99,10 +99,10 @@ ieee754@^1.1.13:
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
   integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
 
 
-import-meta-resolve@^2.1.0:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-2.2.2.tgz#75237301e72d1f0fbd74dbc6cca9324b164c2cc9"
-  integrity sha512-f8KcQ1D80V7RnqVm+/lirO9zkOxjGxhaTC1IPrBGd3MEfNgmNG67tSUO9gTi2F3Blr2Az6g1vocaxzkVnWl9MA==
+import-meta-resolve@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#f9db8bead9fafa61adb811db77a2bf22c5399706"
+  integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==
 
 
 inherits@^2.0.3, inherits@^2.0.4:
 inherits@^2.0.3, inherits@^2.0.4:
   version "2.0.4"
   version "2.0.4"

+ 8 - 7
deps/graph-parser/deps.edn

@@ -1,16 +1,17 @@
 {:paths ["src"]
 {:paths ["src"]
  :deps
  :deps
- ;; External deps should be kept in sync with https://github.com/logseq/nbb-logseq/blob/main/bb.edn
+ ;; These nbb-logseq deps are kept in sync with https://github.com/logseq/nbb-logseq/blob/main/bb.edn
  {com.andrewmcveigh/cljs-time {:git/url "https://github.com/logseq/cljs-time" ;; fork
  {com.andrewmcveigh/cljs-time {:git/url "https://github.com/logseq/cljs-time" ;; fork
                                :sha     "5704fbf48d3478eedcf24d458c8964b3c2fd59a9"}
                                :sha     "5704fbf48d3478eedcf24d458c8964b3c2fd59a9"}
-  ;; local deps
+  funcool/promesa             {:mvn/version "11.0.678"}
+  cljs-bean/cljs-bean         {:mvn/version "1.5.0"}
+
+  ;; Any other deps should be added here and to nbb.edn
+  borkdude/rewrite-edn {:mvn/version "0.4.9"}
   logseq/db                   {:local/root "../db"}
   logseq/db                   {:local/root "../db"}
   logseq/common               {:local/root "../common"}
   logseq/common               {:local/root "../common"}
-  ;; stubbed in nbb
-  com.lambdaisland/glogi      {:mvn/version "1.1.144"}
-  ;; built in to nbb
-  funcool/promesa             {:mvn/version "11.0.678"}
-  cljs-bean/cljs-bean         {:mvn/version "1.5.0"}}
+  ;; stubbed via logseq.common.log
+  com.lambdaisland/glogi      {:mvn/version "1.1.144"}}
 
 
  :aliases
  :aliases
  ;; This runs tests with nodejs. Would be nice to run this with in a browser env
  ;; This runs tests with nodejs. Would be nice to run this with in a browser env

+ 1 - 0
deps/graph-parser/nbb.edn

@@ -6,4 +6,5 @@
   {:local/root "../db"}
   {:local/root "../db"}
   io.github.nextjournal/nbb-test-runner
   io.github.nextjournal/nbb-test-runner
   {:git/sha "60ed57aa04bca8d604f5ba6b28848bd887109347"}
   {:git/sha "60ed57aa04bca8d604f5ba6b28848bd887109347"}
+  borkdude/rewrite-edn {:mvn/version "0.4.9"}
   io.github.pez/baldr {:mvn/version "1.0.9"}}}
   io.github.pez/baldr {:mvn/version "1.0.9"}}}

+ 2 - 2
deps/graph-parser/package.json

@@ -3,8 +3,8 @@
   "version": "1.0.0",
   "version": "1.0.0",
   "private": true,
   "private": true,
   "devDependencies": {
   "devDependencies": {
-    "@logseq/nbb-logseq": "logseq/nbb-logseq#feat-db-v20",
-    "better-sqlite3": "9.3.0"
+    "@logseq/nbb-logseq": "logseq/nbb-logseq#feat-db-v23",
+    "better-sqlite3": "11.10.0"
   },
   },
   "dependencies": {
   "dependencies": {
     "mldoc": "^1.5.9"
     "mldoc": "^1.5.9"

+ 22 - 7
deps/graph-parser/src/logseq/graph_parser/exporter.cljs

@@ -1,7 +1,8 @@
 (ns logseq.graph-parser.exporter
 (ns logseq.graph-parser.exporter
   "Exports a file graph to DB graph. Used by the File to DB graph importer and
   "Exports a file graph to DB graph. Used by the File to DB graph importer and
   by nbb-logseq CLIs"
   by nbb-logseq CLIs"
-  (:require [cljs-time.coerce :as tc]
+  (:require [borkdude.rewrite-edn :as rewrite]
+            [cljs-time.coerce :as tc]
             [cljs.pprint]
             [cljs.pprint]
             [clojure.edn :as edn]
             [clojure.edn :as edn]
             [clojure.set :as set]
             [clojure.set :as set]
@@ -17,6 +18,7 @@
             [logseq.common.uuid :as common-uuid]
             [logseq.common.uuid :as common-uuid]
             [logseq.db :as ldb]
             [logseq.db :as ldb]
             [logseq.db.common.order :as db-order]
             [logseq.db.common.order :as db-order]
+            [logseq.db.common.property-util :as db-property-util]
             [logseq.db.frontend.class :as db-class]
             [logseq.db.frontend.class :as db-class]
             [logseq.db.frontend.content :as db-content]
             [logseq.db.frontend.content :as db-content]
             [logseq.db.frontend.db-ident :as db-ident]
             [logseq.db.frontend.db-ident :as db-ident]
@@ -29,8 +31,7 @@
             [logseq.graph-parser.block :as gp-block]
             [logseq.graph-parser.block :as gp-block]
             [logseq.graph-parser.extract :as extract]
             [logseq.graph-parser.extract :as extract]
             [logseq.graph-parser.property :as gp-property]
             [logseq.graph-parser.property :as gp-property]
-            [promesa.core :as p]
-            [logseq.db.common.property-util :as db-property-util]))
+            [promesa.core :as p]))
 
 
 (defn- add-missing-timestamps
 (defn- add-missing-timestamps
   "Add updated-at or created-at timestamps if they doesn't exist"
   "Add updated-at or created-at timestamps if they doesn't exist"
@@ -762,6 +763,23 @@
         block'' (replace-namespace-with-parent block' page-names-to-uuids)]
         block'' (replace-namespace-with-parent block' page-names-to-uuids)]
     {:block block'' :properties-tx properties-tx}))
     {:block block'' :properties-tx properties-tx}))
 
 
+(defn- pretty-print-dissoc
+  [s dissoc-keys]
+  (-> (reduce rewrite/dissoc
+              (rewrite/parse-string s)
+              dissoc-keys)
+      str))
+
+(defn- migrate-advanced-query-string [query-str]
+  (try
+    (pretty-print-dissoc query-str [:title :group-by-page? :collapsed?])
+    (catch :default _e
+      ;; rewrite/parse-string can fail on some queries in Advanced Queries in docs graph
+      (js/console.error "Failed to parse advanced query string. Falling back to full query string: " (pr-str query-str))
+      (if-let [query-map (not-empty (common-util/safe-read-map-string query-str))]
+        (pr-str (dissoc query-map :title :group-by-page? :collapsed?))
+        query-str))))
+
 (defn- handle-block-properties
 (defn- handle-block-properties
   "Does everything page properties does and updates a couple of block specific attributes"
   "Does everything page properties does and updates a couple of block specific attributes"
   [{:block/keys [title] :as block*}
   [{:block/keys [title] :as block*}
@@ -777,10 +795,7 @@
                                                string/trim)
                                                string/trim)
                                       title))
                                       title))
                            (seq advanced-query)
                            (seq advanced-query)
-                           (assoc :logseq.property/query
-                                  (if-let [query-map (not-empty (common-util/safe-read-map-string advanced-query))]
-                                    (pr-str (dissoc query-map :title :group-by-page? :collapsed?))
-                                    advanced-query)))
+                           (assoc :logseq.property/query (migrate-advanced-query-string advanced-query)))
         {:keys [block-properties pvalues-tx]}
         {:keys [block-properties pvalues-tx]}
         (when (seq additional-props)
         (when (seq additional-props)
           (build-properties-and-values additional-props db page-names-to-uuids
           (build-properties-and-values additional-props db page-names-to-uuids

+ 2 - 2
deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs

@@ -173,7 +173,7 @@
       (is (= 25 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Journal]] @conn))))
       (is (= 25 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Journal]] @conn))))
 
 
       (is (= 4 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Task]] @conn))))
       (is (= 4 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Task]] @conn))))
-      (is (= 3 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Query]] @conn))))
+      (is (= 4 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Query]] @conn))))
       (is (= 2 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Card]] @conn))))
       (is (= 2 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Card]] @conn))))
 
 
       ;; Properties and tags aren't included in this count as they aren't a Page
       ;; Properties and tags aren't included in this count as they aren't a Page
@@ -520,7 +520,7 @@
         "Correct number of user classes")
         "Correct number of user classes")
 
 
     (is (= 4 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Task]] @conn))))
     (is (= 4 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Task]] @conn))))
-    (is (= 3 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Query]] @conn))))
+    (is (= 4 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Query]] @conn))))
     (is (= 2 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Card]] @conn))))
     (is (= 2 (count (d/q '[:find ?b :where [?b :block/tags :logseq.class/Card]] @conn))))
 
 
     (testing "replacing refs in :block/title when :remove-inline-tags? set"
     (testing "replacing refs in :block/title when :remove-inline-tags? set"

+ 22 - 1
deps/graph-parser/test/resources/exporter-test-graph/journals/2024_08_07.md

@@ -1,5 +1,5 @@
 - For example, here's a query with title text:
 - For example, here's a query with title text:
-{{query (property type book)}}
+  {{query (property type book)}}
 - test multilines in this page
 - test multilines in this page
 - |markdown| table|
 - |markdown| table|
   |some|thing|
   |some|thing|
@@ -21,3 +21,24 @@
   :query (task todo doing)}
   :query (task todo doing)}
   #+END_QUERY
   #+END_QUERY
   Text after
   Text after
+- collapsed:: true
+  #+BEGIN_QUERY
+  {:title "⌛ Pretty print advanced query test"
+    :query [:find (pull ?b [*])
+       :in $ ?today
+       :where
+       [?b :block/page ?p]
+       [?p :page/journal? true]
+       [?p :page/journal-day ?jd]
+       [(str ?jd) ?jds]
+       [(subs ?jds 4 8) ?md1]
+       [(str ?today) ?td]
+       [(subs ?td 4 8) ?md2]
+       [(= ?md1 ?md2)]
+       [(< ?jd ?today)]
+    ]
+    :inputs [:today]
+    :breadcrumb-show? true
+    :collapsed? False
+  }
+  #+END_QUERY

+ 0 - 2
deps/graph-parser/test/resources/exporter-test-graph/logseq/config.edn

@@ -208,7 +208,6 @@
             [?h :block/marker ?marker]
             [?h :block/marker ?marker]
             [(contains? #{"NOW" "DOING"} ?marker)]
             [(contains? #{"NOW" "DOING"} ?marker)]
             [?h :block/page ?p]
             [?h :block/page ?p]
-            [?p :block/journal? true]
             [?p :block/journal-day ?d]
             [?p :block/journal-day ?d]
             [(>= ?d ?start)]
             [(>= ?d ?start)]
             [(<= ?d ?today)]]
             [(<= ?d ?today)]]
@@ -225,7 +224,6 @@
             [?h :block/marker ?marker]
             [?h :block/marker ?marker]
             [(contains? #{"NOW" "LATER" "TODO"} ?marker)]
             [(contains? #{"NOW" "LATER" "TODO"} ?marker)]
             [?h :block/page ?p]
             [?h :block/page ?p]
-            [?p :block/journal? true]
             [?p :block/journal-day ?d]
             [?p :block/journal-day ?d]
             [(> ?d ?start)]
             [(> ?d ?start)]
             [(< ?d ?next)]]
             [(< ?d ?next)]]

+ 12 - 12
deps/graph-parser/yarn.lock

@@ -2,11 +2,11 @@
 # yarn lockfile v1
 # yarn lockfile v1
 
 
 
 
-"@logseq/nbb-logseq@logseq/nbb-logseq#feat-db-v20":
-  version "1.2.173-feat-db-v20"
-  resolved "https://codeload.github.com/logseq/nbb-logseq/tar.gz/7fb63423ab566717cac79e5f76084d89b845fbd6"
+"@logseq/nbb-logseq@logseq/nbb-logseq#feat-db-v23":
+  version "1.2.173-feat-db-v23"
+  resolved "https://codeload.github.com/logseq/nbb-logseq/tar.gz/810782c4ddba6346c4ab8ae6740b60438c07cd01"
   dependencies:
   dependencies:
-    import-meta-resolve "^2.1.0"
+    import-meta-resolve "^4.1.0"
 
 
 ansi-regex@^2.0.0:
 ansi-regex@^2.0.0:
   version "2.1.1"
   version "2.1.1"
@@ -23,10 +23,10 @@ base64-js@^1.3.1:
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
   integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
 
 
-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==
+better-sqlite3@11.10.0:
+  version "11.10.0"
+  resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.10.0.tgz#2b1b14c5acd75a43fd84d12cc291ea98cef57d98"
+  integrity sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==
   dependencies:
   dependencies:
     bindings "^1.5.0"
     bindings "^1.5.0"
     prebuild-install "^7.1.1"
     prebuild-install "^7.1.1"
@@ -176,10 +176,10 @@ ieee754@^1.1.13:
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
   integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
 
 
-import-meta-resolve@^2.1.0:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-2.2.2.tgz#75237301e72d1f0fbd74dbc6cca9324b164c2cc9"
-  integrity sha512-f8KcQ1D80V7RnqVm+/lirO9zkOxjGxhaTC1IPrBGd3MEfNgmNG67tSUO9gTi2F3Blr2Az6g1vocaxzkVnWl9MA==
+import-meta-resolve@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#f9db8bead9fafa61adb811db77a2bf22c5399706"
+  integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==
 
 
 inherits@^2.0.3, inherits@^2.0.4:
 inherits@^2.0.3, inherits@^2.0.4:
   version "2.0.4"
   version "2.0.4"

+ 4 - 2
deps/outliner/deps.edn

@@ -1,10 +1,12 @@
 {:deps
 {:deps
- ;; External deps should be kept in sync with https://github.com/logseq/nbb-logseq/blob/main/bb.edn
+ ;; These nbb-logseq deps are kept in sync with https://github.com/logseq/nbb-logseq/blob/main/bb.edn
  {datascript/datascript {:git/url "https://github.com/logseq/datascript" ;; fork
  {datascript/datascript {:git/url "https://github.com/logseq/datascript" ;; fork
                          :sha     "4b1f15f05a6b4a718a62c247956206480e361ea6"}
                          :sha     "4b1f15f05a6b4a718a62c247956206480e361ea6"}
+  com.cognitect/transit-cljs {:mvn/version "0.8.280"}
+
+  ;; Any other deps should be added here and to nbb.edn
   logseq/db             {:local/root "../db"}
   logseq/db             {:local/root "../db"}
   logseq/graph-parser   {:local/root "../db"}
   logseq/graph-parser   {:local/root "../db"}
-  com.cognitect/transit-cljs {:mvn/version "0.8.280"}
   metosin/malli {:mvn/version "0.16.1"}}
   metosin/malli {:mvn/version "0.16.1"}}
  :aliases
  :aliases
  {:clj-kondo
  {:clj-kondo

+ 2 - 2
deps/outliner/package.json

@@ -3,10 +3,10 @@
   "version": "1.0.0",
   "version": "1.0.0",
   "private": true,
   "private": true,
   "devDependencies": {
   "devDependencies": {
-    "@logseq/nbb-logseq": "logseq/nbb-logseq#feat-db-v20"
+    "@logseq/nbb-logseq": "logseq/nbb-logseq#feat-db-v23"
   },
   },
   "dependencies": {
   "dependencies": {
-    "better-sqlite3": "9.3.0",
+    "better-sqlite3": "11.10.0",
     "mldoc": "^1.5.9"
     "mldoc": "^1.5.9"
   },
   },
   "scripts": {
   "scripts": {

+ 12 - 12
deps/outliner/yarn.lock

@@ -2,11 +2,11 @@
 # yarn lockfile v1
 # yarn lockfile v1
 
 
 
 
-"@logseq/nbb-logseq@logseq/nbb-logseq#feat-db-v20":
-  version "1.2.173-feat-db-v20"
-  resolved "https://codeload.github.com/logseq/nbb-logseq/tar.gz/7fb63423ab566717cac79e5f76084d89b845fbd6"
+"@logseq/nbb-logseq@logseq/nbb-logseq#feat-db-v23":
+  version "1.2.173-feat-db-v23"
+  resolved "https://codeload.github.com/logseq/nbb-logseq/tar.gz/810782c4ddba6346c4ab8ae6740b60438c07cd01"
   dependencies:
   dependencies:
-    import-meta-resolve "^2.1.0"
+    import-meta-resolve "^4.1.0"
 
 
 ansi-regex@^2.0.0:
 ansi-regex@^2.0.0:
   version "2.1.1"
   version "2.1.1"
@@ -23,10 +23,10 @@ base64-js@^1.3.1:
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
   integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
 
 
-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==
+better-sqlite3@11.10.0:
+  version "11.10.0"
+  resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.10.0.tgz#2b1b14c5acd75a43fd84d12cc291ea98cef57d98"
+  integrity sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==
   dependencies:
   dependencies:
     bindings "^1.5.0"
     bindings "^1.5.0"
     prebuild-install "^7.1.1"
     prebuild-install "^7.1.1"
@@ -176,10 +176,10 @@ ieee754@^1.1.13:
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
   integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
 
 
-import-meta-resolve@^2.1.0:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-2.2.2.tgz#75237301e72d1f0fbd74dbc6cca9324b164c2cc9"
-  integrity sha512-f8KcQ1D80V7RnqVm+/lirO9zkOxjGxhaTC1IPrBGd3MEfNgmNG67tSUO9gTi2F3Blr2Az6g1vocaxzkVnWl9MA==
+import-meta-resolve@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#f9db8bead9fafa61adb811db77a2bf22c5399706"
+  integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==
 
 
 inherits@^2.0.3, inherits@^2.0.4:
 inherits@^2.0.3, inherits@^2.0.4:
   version "2.0.4"
   version "2.0.4"

+ 2 - 2
deps/publishing/package.json

@@ -3,11 +3,11 @@
   "version": "1.0.0",
   "version": "1.0.0",
   "private": true,
   "private": true,
   "devDependencies": {
   "devDependencies": {
-    "@logseq/nbb-logseq": "logseq/nbb-logseq#feat-db-v20",
+    "@logseq/nbb-logseq": "logseq/nbb-logseq#feat-db-v23",
     "mldoc": "^1.5.9"
     "mldoc": "^1.5.9"
   },
   },
   "dependencies": {
   "dependencies": {
-    "better-sqlite3": "9.3.0",
+    "better-sqlite3": "11.10.0",
     "fs-extra": "9.1.0"
     "fs-extra": "9.1.0"
   },
   },
   "scripts": {
   "scripts": {

+ 12 - 12
deps/publishing/yarn.lock

@@ -2,11 +2,11 @@
 # yarn lockfile v1
 # yarn lockfile v1
 
 
 
 
-"@logseq/nbb-logseq@logseq/nbb-logseq#feat-db-v20":
-  version "1.2.173-feat-db-v20"
-  resolved "https://codeload.github.com/logseq/nbb-logseq/tar.gz/7fb63423ab566717cac79e5f76084d89b845fbd6"
+"@logseq/nbb-logseq@logseq/nbb-logseq#feat-db-v23":
+  version "1.2.173-feat-db-v23"
+  resolved "https://codeload.github.com/logseq/nbb-logseq/tar.gz/810782c4ddba6346c4ab8ae6740b60438c07cd01"
   dependencies:
   dependencies:
-    import-meta-resolve "^2.1.0"
+    import-meta-resolve "^4.1.0"
 
 
 ansi-regex@^2.0.0:
 ansi-regex@^2.0.0:
   version "2.1.1"
   version "2.1.1"
@@ -28,10 +28,10 @@ base64-js@^1.3.1:
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
   integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
 
 
-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==
+better-sqlite3@11.10.0:
+  version "11.10.0"
+  resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.10.0.tgz#2b1b14c5acd75a43fd84d12cc291ea98cef57d98"
+  integrity sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==
   dependencies:
   dependencies:
     bindings "^1.5.0"
     bindings "^1.5.0"
     prebuild-install "^7.1.1"
     prebuild-install "^7.1.1"
@@ -196,10 +196,10 @@ ieee754@^1.1.13:
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
   integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
 
 
-import-meta-resolve@^2.1.0:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-2.2.2.tgz#75237301e72d1f0fbd74dbc6cca9324b164c2cc9"
-  integrity sha512-f8KcQ1D80V7RnqVm+/lirO9zkOxjGxhaTC1IPrBGd3MEfNgmNG67tSUO9gTi2F3Blr2Az6g1vocaxzkVnWl9MA==
+import-meta-resolve@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#f9db8bead9fafa61adb811db77a2bf22c5399706"
+  integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==
 
 
 inherits@^2.0.3, inherits@^2.0.4:
 inherits@^2.0.3, inherits@^2.0.4:
   version "2.0.4"
   version "2.0.4"

+ 5 - 4
package.json

@@ -3,6 +3,9 @@
     "version": "0.0.1",
     "version": "0.0.1",
     "private": true,
     "private": true,
     "main": "static/electron.js",
     "main": "static/electron.js",
+    "engines" : {
+      "node" : ">=22.15.0"
+    },
     "devDependencies": {
     "devDependencies": {
         "@axe-core/playwright": "=4.4.4",
         "@axe-core/playwright": "=4.4.4",
         "@capacitor/cli": "7.2.0",
         "@capacitor/cli": "7.2.0",
@@ -118,8 +121,7 @@
         "@js-joda/core": "3.2.0",
         "@js-joda/core": "3.2.0",
         "@js-joda/locale_en-us": "3.1.1",
         "@js-joda/locale_en-us": "3.1.1",
         "@js-joda/timezone": "2.5.0",
         "@js-joda/timezone": "2.5.0",
-        "@logseq/capacitor-file-sync": "5.0.2",
-        "@logseq/diff-merge": "0.2.2",
+        "@logseq/diff-merge": "^0.2.2",
         "@logseq/react-tweet-embed": "1.3.1-1",
         "@logseq/react-tweet-embed": "1.3.1-1",
         "@logseq/sqlite-wasm": "=0.1.0",
         "@logseq/sqlite-wasm": "=0.1.0",
         "@radix-ui/colors": "^0.1.8",
         "@radix-ui/colors": "^0.1.8",
@@ -138,7 +140,7 @@
         "d3-force": "3.0.0",
         "d3-force": "3.0.0",
         "diff": "5.0.0",
         "diff": "5.0.0",
         "dompurify": "2.4.0",
         "dompurify": "2.4.0",
-        "electron": "35.0.1",
+        "electron": "36.2.0",
         "electron-dl": "^4.0.0",
         "electron-dl": "^4.0.0",
         "emoji-mart": "^5.5.2",
         "emoji-mart": "^5.5.2",
         "fs": "0.0.1-security",
         "fs": "0.0.1-security",
@@ -171,7 +173,6 @@
         "react-transition-group": "4.3.0",
         "react-transition-group": "4.3.0",
         "react-virtuoso": "4.12.5",
         "react-virtuoso": "4.12.5",
         "remove-accents": "0.4.2",
         "remove-accents": "0.4.2",
-        "reveal.js": "^4.5.0",
         "sanitize-filename": "1.6.3",
         "sanitize-filename": "1.6.3",
         "send-intent": "^5.0.0",
         "send-intent": "^5.0.0",
         "shepherd.js": "^9.1.0",
         "shepherd.js": "^9.1.0",

+ 1 - 1
resources/forge.config.js

@@ -5,7 +5,7 @@ module.exports = {
   packagerConfig: {
   packagerConfig: {
     name: 'Logseq',
     name: 'Logseq',
     icon: './icons/logseq_big_sur.icns',
     icon: './icons/logseq_big_sur.icns',
-    buildVersion: 84,
+    buildVersion: "85",
     protocols: [
     protocols: [
       {
       {
         "protocol": "logseq",
         "protocol": "logseq",

+ 0 - 45
resources/js/preload.js

@@ -107,51 +107,6 @@ contextBridge.exposeInMainWorld('apis', {
     )
     )
   },
   },
 
 
-  /**
-   * When from is empty. The resource maybe from
-   * client paste or screenshoot.
-   * @param repoPathRoot
-   * @param to
-   * @param from?
-   * @returns {Promise<void>}
-   */
-  async copyFileToAssets (repoPathRoot, to, from) {
-    if (from && fs.statSync(from).isDirectory()) {
-      throw new Error('not support copy directory')
-    }
-
-    const dest = path.join(repoPathRoot, to)
-    const assetsRoot = path.dirname(dest)
-
-    await fs.promises.mkdir(assetsRoot, { recursive: true })
-
-    from = from || getFilePathFromClipboard()
-
-    if (from) {
-      try {
-        // console.debug('copy file: ', from, dest)
-        await fs.promises.copyFile(from, dest)
-        return path.basename(from)
-      } catch (e) {
-        from = decodeURIComponent(from)
-        await fs.promises.copyFile(from, dest)
-        return path.basename(from)
-      }
-    }
-
-    // support image
-    // console.debug('read image: ', from, dest)
-    const nImg = clipboard.readImage()
-
-    if (nImg && !nImg.isEmpty()) {
-      const rawExt = path.extname(dest)
-      return await fs.promises.writeFile(
-        dest.replace(rawExt, '.png'),
-        nImg.toPNG()
-      )
-    }
-  },
-
   toggleMaxOrMinActiveWindow (isToggleMin = false) {
   toggleMaxOrMinActiveWindow (isToggleMin = false) {
     ipcRenderer.invoke('toggle-max-or-min-active-win', isToggleMin)
     ipcRenderer.invoke('toggle-max-or-min-active-win', isToggleMin)
   },
   },

+ 15 - 15
resources/package.json

@@ -14,14 +14,14 @@
     "electron:make-linux-arm64": "electron-forge make --platform=linux --arch=arm64",
     "electron:make-linux-arm64": "electron-forge make --platform=linux --arch=arm64",
     "electron:make-macos-arm64": "electron-forge make --platform=darwin --arch=arm64",
     "electron:make-macos-arm64": "electron-forge make --platform=darwin --arch=arm64",
     "electron:publish:github": "electron-forge publish",
     "electron:publish:github": "electron-forge publish",
-    "rebuild:all": "electron-rebuild -v 35.0.1 -f",
+    "rebuild:all": "electron-rebuild -v 36.2.0 -f",
     "postinstall": "install-app-deps"
     "postinstall": "install-app-deps"
   },
   },
   "config": {
   "config": {
     "forge": "./forge.config.js"
     "forge": "./forge.config.js"
   },
   },
   "dependencies": {
   "dependencies": {
-    "@fastify/cors": "10.0.1",
+    "@fastify/cors": "11.0.1",
     "@logseq/rsapi": "0.0.91",
     "@logseq/rsapi": "0.0.91",
     "@sentry/electron": "2.5.1",
     "@sentry/electron": "2.5.1",
     "abort-controller": "3.0.0",
     "abort-controller": "3.0.0",
@@ -35,7 +35,7 @@
     "electron-squirrel-startup": "1.0.0",
     "electron-squirrel-startup": "1.0.0",
     "electron-window-state": "5.0.3",
     "electron-window-state": "5.0.3",
     "extract-zip": "2.0.1",
     "extract-zip": "2.0.1",
-    "fastify": "5.1.0",
+    "fastify": "5.3.2",
     "fs-extra": "9.1.0",
     "fs-extra": "9.1.0",
     "https-proxy-agent": "7.0.2",
     "https-proxy-agent": "7.0.2",
     "node-fetch": "2.6.7",
     "node-fetch": "2.6.7",
@@ -46,22 +46,22 @@
     "update-electron-app": "2.0.1"
     "update-electron-app": "2.0.1"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "@electron-forge/cli": "^7.3.1",
-    "@electron-forge/maker-deb": "^7.3.1",
-    "@electron-forge/maker-dmg": "^7.3.1",
-    "@electron-forge/maker-wix": "^7.3.1",
-    "@electron-forge/maker-rpm": "^7.3.1",
-    "@electron-forge/maker-squirrel": "^7.3.1",
-    "@electron-forge/maker-zip": "^7.3.1",
-    "@electron/rebuild": "3.2.10",
-    "electron": "35.0.1",
-    "electron-builder": "25.1.8",
+    "@electron-forge/cli": "^7.8.0",
+    "@electron-forge/maker-deb": "^7.8.0",
+    "@electron-forge/maker-dmg": "^7.8.0",
+    "@electron-forge/maker-wix": "^7.8.0",
+    "@electron-forge/maker-rpm": "^7.8.0",
+    "@electron-forge/maker-squirrel": "^7.8.0",
+    "@electron-forge/maker-zip": "^7.8.0",
+    "@electron/rebuild": "4.0.1",
+    "electron": "36.2.0",
+    "electron-builder": "26.0.12",
     "electron-forge-maker-appimage": "https://github.com/logseq/electron-forge-maker-appimage.git",
     "electron-forge-maker-appimage": "https://github.com/logseq/electron-forge-maker-appimage.git",
     "electron-devtools-installer": "^3.2.0"
     "electron-devtools-installer": "^3.2.0"
   },
   },
   "resolutions": {
   "resolutions": {
-    "**/electron": "35.0.1",
-    "**/node-abi": "3.74.0",
+    "**/electron": "36.2.0",
+    "**/node-abi": "3.75.0",
     "**/node-gyp": "11.1.0",
     "**/node-gyp": "11.1.0",
     "string-width": "4.2.0",
     "string-width": "4.2.0",
     "wrap-ansi": "^7.0.0",
     "wrap-ansi": "^7.0.0",

+ 2 - 2
scripts/package.json

@@ -3,10 +3,10 @@
   "version": "1.0.0",
   "version": "1.0.0",
   "private": true,
   "private": true,
   "devDependencies": {
   "devDependencies": {
-    "@logseq/nbb-logseq": "logseq/nbb-logseq#feat-db-v20"
+    "@logseq/nbb-logseq": "logseq/nbb-logseq#feat-db-v23"
   },
   },
   "dependencies": {
   "dependencies": {
-    "better-sqlite3": "9.3.0",
+    "better-sqlite3": "11.10.0",
     "fs-extra": "9.1.0",
     "fs-extra": "9.1.0",
     "mldoc": "^1.5.9"
     "mldoc": "^1.5.9"
   }
   }

+ 5 - 5
scripts/src/logseq/tasks/lang.clj

@@ -7,7 +7,7 @@
             [babashka.cli :as cli]
             [babashka.cli :as cli]
             [babashka.process :refer [shell]]
             [babashka.process :refer [shell]]
             [babashka.fs :as fs]
             [babashka.fs :as fs]
-            [borkdude.rewrite-edn :as r]))
+            [borkdude.rewrite-edn :as rewrite]))
 
 
 (defn- get-dicts
 (defn- get-dicts
   []
   []
@@ -78,10 +78,10 @@
   [invalid-keys-by-lang]
   [invalid-keys-by-lang]
   (doseq [[lang invalid-keys] invalid-keys-by-lang]
   (doseq [[lang invalid-keys] invalid-keys-by-lang]
     (let [path (fs/path "src/resources/dicts" (str (name lang) ".edn"))
     (let [path (fs/path "src/resources/dicts" (str (name lang) ".edn"))
-          result (r/parse-string (String. (fs/read-all-bytes path)))
+          result (rewrite/parse-string (String. (fs/read-all-bytes path)))
           new-content (str (reduce
           new-content (str (reduce
                             (fn [result k]
                             (fn [result k]
-                              (r/dissoc result k))
+                              (rewrite/dissoc result k))
                             result invalid-keys))]
                             result invalid-keys))]
       (spit (fs/file path) new-content))))
       (spit (fs/file path) new-content))))
 
 
@@ -148,10 +148,10 @@
   [invalid-keys]
   [invalid-keys]
   (let [paths (fs/list-dir "src/resources/dicts")]
   (let [paths (fs/list-dir "src/resources/dicts")]
     (doseq [path paths]
     (doseq [path paths]
-      (let [result (r/parse-string (String. (fs/read-all-bytes path)))
+      (let [result (rewrite/parse-string (String. (fs/read-all-bytes path)))
             new-content (str (reduce
             new-content (str (reduce
                               (fn [result k]
                               (fn [result k]
-                                (r/dissoc result k))
+                                (rewrite/dissoc result k))
                               result invalid-keys))]
                               result invalid-keys))]
         (spit (fs/file path) new-content)))))
         (spit (fs/file path) new-content)))))
 
 

+ 12 - 12
scripts/yarn.lock

@@ -2,11 +2,11 @@
 # yarn lockfile v1
 # yarn lockfile v1
 
 
 
 
-"@logseq/nbb-logseq@logseq/nbb-logseq#feat-db-v20":
-  version "1.2.173-feat-db-v20"
-  resolved "https://codeload.github.com/logseq/nbb-logseq/tar.gz/7fb63423ab566717cac79e5f76084d89b845fbd6"
+"@logseq/nbb-logseq@logseq/nbb-logseq#feat-db-v23":
+  version "1.2.173-feat-db-v23"
+  resolved "https://codeload.github.com/logseq/nbb-logseq/tar.gz/810782c4ddba6346c4ab8ae6740b60438c07cd01"
   dependencies:
   dependencies:
-    import-meta-resolve "^2.1.0"
+    import-meta-resolve "^4.1.0"
 
 
 ansi-regex@^2.0.0:
 ansi-regex@^2.0.0:
   version "2.1.1"
   version "2.1.1"
@@ -28,10 +28,10 @@ base64-js@^1.3.1:
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
   integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
 
 
-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==
+better-sqlite3@11.10.0:
+  version "11.10.0"
+  resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-11.10.0.tgz#2b1b14c5acd75a43fd84d12cc291ea98cef57d98"
+  integrity sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==
   dependencies:
   dependencies:
     bindings "^1.5.0"
     bindings "^1.5.0"
     prebuild-install "^7.1.1"
     prebuild-install "^7.1.1"
@@ -196,10 +196,10 @@ ieee754@^1.1.13:
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
   integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
 
 
-import-meta-resolve@^2.1.0:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-2.2.2.tgz#75237301e72d1f0fbd74dbc6cca9324b164c2cc9"
-  integrity sha512-f8KcQ1D80V7RnqVm+/lirO9zkOxjGxhaTC1IPrBGd3MEfNgmNG67tSUO9gTi2F3Blr2Az6g1vocaxzkVnWl9MA==
+import-meta-resolve@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#f9db8bead9fafa61adb811db77a2bf22c5399706"
+  integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==
 
 
 inherits@^2.0.3, inherits@^2.0.4:
 inherits@^2.0.3, inherits@^2.0.4:
   version "2.0.4"
   version "2.0.4"

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

@@ -13,7 +13,7 @@
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
             [frontend.handler.plugin :as plugin-handler]
             [frontend.handler.plugin :as plugin-handler]
             [frontend.handler.property.file :as property-file]
             [frontend.handler.property.file :as property-file]
-            [frontend.ref :as ref]
+            [frontend.util.ref :as ref]
             [frontend.search :as search]
             [frontend.search :as search]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.util :as util]
             [frontend.util :as util]

+ 2 - 4
src/main/frontend/components/block.cljs

@@ -62,7 +62,7 @@
             [frontend.mobile.util :as mobile-util]
             [frontend.mobile.util :as mobile-util]
             [frontend.modules.outliner.tree :as tree]
             [frontend.modules.outliner.tree :as tree]
             [frontend.modules.shortcut.utils :as shortcut-utils]
             [frontend.modules.shortcut.utils :as shortcut-utils]
-            [frontend.ref :as ref]
+            [frontend.util.ref :as ref]
             [frontend.security :as security]
             [frontend.security :as security]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.template :as template]
             [frontend.template :as template]
@@ -458,7 +458,7 @@
                  (let [repo (state/get-current-repo)
                  (let [repo (state/get-current-repo)
                        file-rpath (string/replace s #"^[.\/\\]*assets[\/\\]+" "assets/")
                        file-rpath (string/replace s #"^[.\/\\]*assets[\/\\]+" "assets/")
                        dir (config/get-repo-dir repo)]
                        dir (config/get-repo-dir repo)]
-                   (-> (fs/write-file! repo dir file-rpath content nil)
+                   (-> (fs/write-plain-text-file! repo dir file-rpath content nil)
                        (p/then load$)))))
                        (p/then load$)))))
              (js/console.error _e)))))))
              (js/console.error _e)))))))
 
 
@@ -467,11 +467,9 @@
   [state config title href metadata full_text]
   [state config title href metadata full_text]
   (let [src (::src state)
   (let [src (::src state)
         repo (state/get-current-repo)
         repo (state/get-current-repo)
-        granted? (state/sub [:nfs/user-granted? repo])
         href (config/get-local-asset-absolute-path href)
         href (config/get-local-asset-absolute-path href)
         db-based? (config/db-based-graph? repo)]
         db-based? (config/db-based-graph? repo)]
     (when (and (or db-based?
     (when (and (or db-based?
-                   granted?
                    (util/electron?)
                    (util/electron?)
                    (mobile-util/native-platform?))
                    (mobile-util/native-platform?))
                (nil? @src))
                (nil? @src))

+ 12 - 11
src/main/frontend/components/block/macros.cljs

@@ -13,16 +13,18 @@
 
 
 (defn- properties-by-name
 (defn- properties-by-name
   "Given a block from a query result, returns a map of its properties indexed by
   "Given a block from a query result, returns a map of its properties indexed by
-  property names"
+  property idents and titles"
   [db block]
   [db block]
   (->> (db-property/properties block)
   (->> (db-property/properties block)
-       (map (fn [[k v]]
-              [(:block/title (d/entity db k))
-               ;; For now just support cardinality :one
-               (when-not (set? v)
-                 (some->> (:db/id v)
-                          (d/entity db)
-                          db-property/property-value-content))]))
+       (mapcat (fn [[k v]]
+                 ;; For now just support cardinality :one
+                 (when-not (set? v)
+                   (let [prop-val (some->> (:db/id v)
+                                           (d/entity db)
+                                           db-property/property-value-content)
+                         property (d/entity db k)]
+                     [[(keyword (:block/title property)) prop-val]
+                      [(:db/ident property) prop-val]]))))
        (into {})))
        (into {})))
 
 
 (defn- normalize-query-function
 (defn- normalize-query-function
@@ -55,11 +57,10 @@
          (keyword? f)
          (keyword? f)
          (if-let [kw (and (not db-based-graph?) (get special-file-graph-keywords f))]
          (if-let [kw (and (not db-based-graph?) (get special-file-graph-keywords f))]
            kw
            kw
-           (let [prop-key (if db-based-graph? (name f) f)
-                 vals (map #(get-in % [:block/properties prop-key]) result)
+           (let [vals (map #(get-in % [:block/properties f]) result)
                  int? (some integer? vals)]
                  int? (some integer? vals)]
              `(~'fn [~'b]
              `(~'fn [~'b]
-                    (~'let [~'result-str (~'get-in ~'b [:block/properties ~prop-key])
+                    (~'let [~'result-str (~'get-in ~'b [:block/properties ~f])
                             ~'result-num (~'parseFloat ~'result-str)
                             ~'result-num (~'parseFloat ~'result-str)
                             ~'result (if (~'isNaN ~'result-num) ~'result-str ~'result-num)]
                             ~'result (if (~'isNaN ~'result-num) ~'result-str ~'result-num)]
                            (~'or ~'result (~'when ~int? 0))))))
                            (~'or ~'result (~'when ~int? 0))))))

+ 12 - 14
src/main/frontend/components/container.cljs

@@ -262,17 +262,17 @@
             :shortcut :go/home})
             :shortcut :go/home})
 
 
           (when enable-journals?
           (when enable-journals?
-           (sidebar-item
-            {:class "journals-nav"
-             :active (and (not srs-open?)
-                          (or (= route-name :all-journals) (= route-name :home)))
-             :title (t :left-side-bar/journals)
-             :on-click-handler (fn [e]
-                                 (if (gobj/get e "shiftKey")
-                                   (route-handler/sidebar-journals!)
-                                   (route-handler/go-to-journals!)))
-             :icon "calendar"
-             :shortcut :go/journals}))))
+            (sidebar-item
+             {:class "journals-nav"
+              :active (and (not srs-open?)
+                           (or (= route-name :all-journals) (= route-name :home)))
+              :title (t :left-side-bar/journals)
+              :on-click-handler (fn [e]
+                                  (if (gobj/get e "shiftKey")
+                                    (route-handler/sidebar-journals!)
+                                    (route-handler/go-to-journals!)))
+              :icon "calendar"
+              :shortcut :go/journals}))))
 
 
       (for [nav checked-navs]
       (for [nav checked-navs]
         (cond
         (cond
@@ -955,7 +955,6 @@
                       (state/set-state! :editor/latest-shortcut nil)))))
                       (state/set-state! :editor/latest-shortcut nil)))))
   [state route-match main-content']
   [state route-match main-content']
   (let [current-repo (state/sub :git/current-repo)
   (let [current-repo (state/sub :git/current-repo)
-        granted? (state/sub [:nfs/user-granted? (state/get-current-repo)])
         theme (state/sub :ui/theme)
         theme (state/sub :ui/theme)
         accent-color (some-> (state/sub :ui/radix-color) (name))
         accent-color (some-> (state/sub :ui/radix-color) (name))
         editor-font (some-> (state/sub :ui/editor-font) (name))
         editor-font (some-> (state/sub :ui/editor-font) (name))
@@ -992,7 +991,7 @@
       :route route-match
       :route route-match
       :current-repo current-repo
       :current-repo current-repo
       :edit? edit?
       :edit? edit?
-      :nfs-granted? granted?
+
       :db-restoring? db-restoring?
       :db-restoring? db-restoring?
       :sidebar-open? sidebar-open?
       :sidebar-open? sidebar-open?
       :settings-open? settings-open?
       :settings-open? settings-open?
@@ -1067,7 +1066,6 @@
       (plugins/custom-js-installer
       (plugins/custom-js-installer
        {:t t
        {:t t
         :current-repo current-repo
         :current-repo current-repo
-        :nfs-granted? granted?
         :db-restoring? db-restoring?})
         :db-restoring? db-restoring?})
       (app-context-menu-observer)
       (app-context-menu-observer)
 
 

+ 1 - 1
src/main/frontend/components/content.cljs

@@ -19,7 +19,7 @@
             [frontend.handler.property :as property-handler]
             [frontend.handler.property :as property-handler]
             [frontend.handler.property.util :as pu]
             [frontend.handler.property.util :as pu]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.modules.shortcut.core :as shortcut]
-            [frontend.ref :as ref]
+            [frontend.util.ref :as ref]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.ui :as ui]
             [frontend.util :as util]
             [frontend.util :as util]

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

@@ -9,11 +9,11 @@
             [frontend.components.onboarding.quick-tour :as quick-tour]
             [frontend.components.onboarding.quick-tour :as quick-tour]
             [frontend.components.page :as page]
             [frontend.components.page :as page]
             [frontend.config :as config]
             [frontend.config :as config]
-            [frontend.db.model :as db-model]
             [frontend.db.file-based.model :as file-model]
             [frontend.db.file-based.model :as file-model]
+            [frontend.db.model :as db-model]
             [frontend.fs :as fs]
             [frontend.fs :as fs]
             [frontend.fs.sync :as fs-sync]
             [frontend.fs.sync :as fs-sync]
-            [frontend.handler.file-based.nfs :as nfs-handler]
+            [frontend.handler.file-based.native-fs :as nfs-handler]
             [frontend.handler.file-sync :refer [*beta-unavailable?] :as file-sync-handler]
             [frontend.handler.file-sync :refer [*beta-unavailable?] :as file-sync-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
             [frontend.handler.page :as page-handler]
             [frontend.handler.page :as page-handler]

+ 29 - 29
src/main/frontend/components/file_sync.css

@@ -6,37 +6,37 @@
 
 
 .cp__file-sync, .cp__rtc-sync {
 .cp__file-sync, .cp__rtc-sync {
   &-indicator {
   &-indicator {
-    .ui__button.cloud {
-      @apply relative;
-
-      &.on {
-        @apply after:content-['*'];
-
-        &:after {
-          @apply absolute bottom-2.5 right-1 w-[7px] h-[7px] rounded-full opacity-100 text-transparent;
-
-          background-color: var(--ls-color-file-sync-pending);
-        }
-
-        &.syncing {
-          &:after {
-            background-color: var(--ls-color-file-sync-pending);
+      .ui__button.cloud {
+          @apply relative;
+
+          &.on {
+              @apply after:content-['*'];
+
+              &:after {
+                  @apply absolute bottom-2.5 right-1 w-[7px] h-[7px] rounded-full opacity-100 text-transparent;
+
+                  background-color: var(--ls-color-file-sync-pending);
+              }
+
+              &.syncing {
+                  &:after {
+                      background-color: var(--ls-color-file-sync-pending);
+                  }
+              }
+
+              &.queuing {
+                  &:after {
+                      background-color: var(--ls-color-file-sync-pending);
+                  }
+              }
+
+              &.idle {
+                  &:after {
+                      background-color: var(--ls-color-file-sync-idle);
+                  }
+              }
           }
           }
-        }
-
-        &.queuing {
-          &:after {
-            background-color: var(--ls-color-file-sync-pending);
-          }
-        }
-
-        &.idle {
-          &:after {
-            background-color: var(--ls-color-file-sync-idle);
-          }
-        }
       }
       }
-    }
 
 
     .debug-status {
     .debug-status {
       position: absolute;
       position: absolute;

+ 1 - 1
src/main/frontend/components/imports.cljs

@@ -345,7 +345,7 @@
                       parent-dir (path/path-join repo-dir (path/dirname (:path file)))]
                       parent-dir (path/path-join repo-dir (path/dirname (:path file)))]
                   (p/do!
                   (p/do!
                    (fs/mkdir-if-not-exists parent-dir)
                    (fs/mkdir-if-not-exists parent-dir)
-                   (fs/write-file! repo repo-dir (:path file) content {:skip-transact? true})))))))
+                   (fs/write-plain-text-file! repo repo-dir (:path file) content {:skip-transact? true})))))))
 
 
 (defn- import-file-graph
 (defn- import-file-graph
   [*files
   [*files

+ 10 - 10
src/main/frontend/components/plugins.cljs

@@ -586,13 +586,13 @@
       (when (and develop-mode? (util/electron?) (not market?))
       (when (and develop-mode? (util/electron?) (not market?))
         [:div
         [:div
          (ui/tooltip
          (ui/tooltip
-           (ui/button
-             (t :plugin/load-unpacked)
-             {:icon "upload"
-              :intent "link"
-              :class "load-unpacked"
-              :on-click plugin-handler/load-unpacked-plugin})
-           [:div (t :plugin/unpacked-tips)])
+          (ui/button
+           (t :plugin/load-unpacked)
+           {:icon "upload"
+            :intent "link"
+            :class "load-unpacked"
+            :on-click plugin-handler/load-unpacked-plugin})
+          [:div (t :plugin/unpacked-tips)])
 
 
          (when (util/electron?)
          (when (util/electron?)
            (unpacked-plugin-loader selected-unpacked-pkg))])]
            (unpacked-plugin-loader selected-unpacked-pkg))])]
@@ -1524,13 +1524,13 @@
             (bean/->clj (.-settingsSchema pl)) pl)))]]]]))
             (bean/->clj (.-settingsSchema pl)) pl)))]]]]))
 
 
 (rum/defc custom-js-installer
 (rum/defc custom-js-installer
-  [{:keys [t current-repo db-restoring? nfs-granted?]}]
+  [{:keys [t current-repo db-restoring?]}]
   (hooks/use-effect!
   (hooks/use-effect!
    (fn []
    (fn []
      (when (and (not db-restoring?)
      (when (and (not db-restoring?)
-                (or (not util/nfs?) nfs-granted?))
+                (not util/nfs?))
        (ui-handler/exec-js-if-exists-&-allowed! t)))
        (ui-handler/exec-js-if-exists-&-allowed! t)))
-   [current-repo db-restoring? nfs-granted?])
+   [current-repo db-restoring?])
   nil)
   nil)
 
 
 (rum/defc perf-tip-content
 (rum/defc perf-tip-content

+ 2 - 1
src/main/frontend/components/property/value.cljs

@@ -1460,7 +1460,8 @@
                   (and (:db/id block)
                   (and (:db/id block)
                        (= p-block (:db/id block))
                        (= p-block (:db/id block))
                        (= p-property (:db/id property))))
                        (= p-property (:db/id property))))
-              (not= :logseq.class/Tag (:db/ident block)))
+              (not= :logseq.class/Tag
+                    (:db/ident (db/entity (:db/id block)))))
        [:div.flex.flex-row.items-center.gap-1
        [:div.flex.flex-row.items-center.gap-1
         [:div.warning "Self reference"]
         [:div.warning "Self reference"]
         (shui/button {:variant :outline
         (shui/button {:variant :outline

+ 1 - 1
src/main/frontend/components/query/builder.cljs

@@ -13,7 +13,7 @@
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.query.builder :as query-builder]
             [frontend.handler.query.builder :as query-builder]
             [frontend.mixins :as mixins]
             [frontend.mixins :as mixins]
-            [frontend.ref :as ref]
+            [frontend.util.ref :as ref]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.ui :as ui]
             [frontend.util :as util]
             [frontend.util :as util]

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

@@ -6,7 +6,7 @@
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.handler.db-based.rtc :as rtc-handler]
             [frontend.handler.db-based.rtc :as rtc-handler]
             [frontend.handler.db-based.rtc-flows :as rtc-flows]
             [frontend.handler.db-based.rtc-flows :as rtc-flows]
-            [frontend.handler.file-based.nfs :as nfs-handler]
+            [frontend.handler.file-based.native-fs :as nfs-handler]
             [frontend.handler.file-sync :as file-sync]
             [frontend.handler.file-sync :as file-sync]
             [frontend.handler.graph :as graph]
             [frontend.handler.graph :as graph]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
@@ -105,7 +105,7 @@
 
 
                      :else
                      :else
                      "Removes Logseq's access to the local file path of your graph. It won't remove your local files.")]
                      "Removes Logseq's access to the local file path of your graph. It won't remove your local files.")]
-         (when-not (and only-cloud? (not manager?))
+         (when-not (and db-graph? only-cloud? (not manager?))
            [:a.text-gray-400.ml-4.font-medium.text-sm.whitespace-nowrap
            [:a.text-gray-400.ml-4.font-medium.text-sm.whitespace-nowrap
             {:title title
             {:title title
              :on-click (fn []
              :on-click (fn []

+ 1 - 1
src/main/frontend/components/right_sidebar.css

@@ -23,7 +23,7 @@ html[data-theme=light] {
 
 
 .cp__header {
 .cp__header {
   > .r > div:not(.ui__dropdown-trigger) a, button {
   > .r > div:not(.ui__dropdown-trigger) a, button {
-    @apply opacity-70;
+    @apply opacity-70 text-[inherit];
 
 
     &:hover {
     &:hover {
       @apply opacity-100;
       @apply opacity-100;

+ 23 - 15
src/main/frontend/components/rtc/indicator.cljs

@@ -4,10 +4,12 @@
             [clojure.pprint :as pprint]
             [clojure.pprint :as pprint]
             [frontend.common.missionary :as c.m]
             [frontend.common.missionary :as c.m]
             [frontend.db :as db]
             [frontend.db :as db]
+            [frontend.flows :as flows]
             [frontend.handler.db-based.rtc-flows :as rtc-flows]
             [frontend.handler.db-based.rtc-flows :as rtc-flows]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.ui :as ui]
             [frontend.util :as util]
             [frontend.util :as util]
+            [logseq.shui.hooks :as hooks]
             [logseq.shui.ui :as shui]
             [logseq.shui.ui :as shui]
             [missionary.core :as m]
             [missionary.core :as m]
             [rum.core :as rum]))
             [rum.core :as rum]))
@@ -55,10 +57,17 @@
       (reset! *update-detail-info-canceler canceler))))
       (reset! *update-detail-info-canceler canceler))))
 (run-task--update-detail-info)
 (run-task--update-detail-info)
 
 
-(rum/defc assets-progressing < rum/reactive
+(defn- asset-upload-download-progress-flow
+  [repo]
+  (->> (m/watch (get @state/state :rtc/asset-upload-download-progress))
+       (m/eduction
+        (keep #(get % repo))
+        (dedupe))))
+
+(rum/defc assets-progressing
   []
   []
   (let [repo (state/get-current-repo)
   (let [repo (state/get-current-repo)
-        progress (state/sub :rtc/asset-upload-download-progress {:path-in-sub-atom [repo]})
+        progress (hooks/use-flow-state (asset-upload-download-progress-flow repo))
         downloading (->>
         downloading (->>
                      (keep (fn [[id {:keys [direction loaded total]}]]
                      (keep (fn [[id {:keys [direction loaded total]}]]
                              (when (and (= direction :download)
                              (when (and (= direction :download)
@@ -96,13 +105,12 @@
             (ui/indicator-progress-pie percent)
             (ui/indicator-progress-pie percent)
             (:block/title block)])]])]))
             (:block/title block)])]])]))
 
 
-(rum/defcs details < rum/reactive
-  (rum/local false ::expand-debug-info?)
-  [state online?]
-  (let [*expand-debug? (::expand-debug-info? state)
+(rum/defc details
+  [online?]
+  (let [[expand-debug? set-expand-debug!] (hooks/use-state false)
         {:keys [graph-uuid local-tx remote-tx rtc-state
         {:keys [graph-uuid local-tx remote-tx rtc-state
                 download-logs upload-logs misc-logs pending-local-ops pending-server-ops]}
                 download-logs upload-logs misc-logs pending-local-ops pending-server-ops]}
-        (rum/react *detail-info)]
+        (hooks/use-flow-state (m/watch *detail-info))]
     [:div.rtc-info.flex.flex-col.gap-1.p-2.text-gray-11
     [:div.rtc-info.flex.flex-col.gap-1.p-2.text-gray-11
      [:div.font-medium.mb-2 (if online? "Online" "Offline")]
      [:div.font-medium.mb-2 (if online? "Online" "Offline")]
      [:div [:span.font-medium.mr-1 (or pending-local-ops 0)] "pending local changes"]
      [:div [:span.font-medium.mr-1 (or pending-local-ops 0)] "pending local changes"]
@@ -115,9 +123,9 @@
        (when-let [time (:created-at latest-log)]
        (when-let [time (:created-at latest-log)]
          [:div.text-sm "Last synced time: "
          [:div.text-sm "Last synced time: "
           (.toLocaleString time)]))
           (.toLocaleString time)]))
-     [:a.fade-link.text-sm {:on-click #(swap! *expand-debug? not)}
+     [:a.fade-link.text-sm {:on-click #(set-expand-debug! (not expand-debug?))}
       "More debug info"]
       "More debug info"]
-     (when @*expand-debug?
+     (when expand-debug?
        [:div.rtc-info-debug
        [:div.rtc-info-debug
         [:pre.select-text
         [:pre.select-text
          (-> (cond-> {:pending-local-ops pending-local-ops}
          (-> (cond-> {:pending-local-ops pending-local-ops}
@@ -145,13 +153,13 @@
          (> 600
          (> 600
             (/ (- (t/now) created-at) 1000)))))
             (/ (- (t/now) created-at) 1000)))))
 
 
-(rum/defc indicator < rum/reactive
+(rum/defc indicator
   []
   []
-  (let [detail-info                 (rum/react *detail-info)
-        _                           (state/sub :auth/id-token)
-        online?                     (state/sub :network/online?)
-        uploading?'                  (uploading? detail-info)
-        downloading?'                (downloading? detail-info)
+  (let [detail-info                 (hooks/use-flow-state (m/watch *detail-info))
+        _                           (hooks/use-flow-state flows/current-login-user-flow)
+        online?                     (hooks/use-flow-state flows/network-online-event-flow)
+        uploading?'                 (uploading? detail-info)
+        downloading?'               (downloading? detail-info)
         rtc-state                   (:rtc-state detail-info)
         rtc-state                   (:rtc-state detail-info)
         unpushed-block-update-count (:pending-local-ops detail-info)
         unpushed-block-update-count (:pending-local-ops detail-info)
         {:keys [local-tx remote-tx]} detail-info]
         {:keys [local-tx remote-tx]} detail-info]

+ 3 - 3
src/main/frontend/components/theme.cljs

@@ -36,7 +36,7 @@
 (defonce *once-theme-loaded? (volatile! false))
 (defonce *once-theme-loaded? (volatile! false))
 
 
 (rum/defc ^:large-vars/cleanup-todo container < rum/static
 (rum/defc ^:large-vars/cleanup-todo container < rum/static
-  [{:keys [route theme accent-color editor-font on-click current-repo nfs-granted? db-restoring?
+  [{:keys [route theme accent-color editor-font on-click current-repo db-restoring?
            settings-open? sidebar-open? system-theme? sidebar-blocks-len onboarding-state preferred-language]} child]
            settings-open? sidebar-open? system-theme? sidebar-blocks-len onboarding-state preferred-language]} child]
   (let [mounted-fn (use-mounted)
   (let [mounted-fn (use-mounted)
         [restored-sidebar? set-restored-sidebar?] (rum/use-state false)]
         [restored-sidebar? set-restored-sidebar?] (rum/use-state false)]
@@ -103,9 +103,9 @@
      #(let [db-restored? (false? db-restoring?)]
      #(let [db-restored? (false? db-restoring?)]
         (if db-restoring?
         (if db-restoring?
           (util/set-title! (t :loading))
           (util/set-title! (t :loading))
-          (when (or nfs-granted? db-restored?)
+          (when db-restored?
             (route-handler/update-page-title! route))))
             (route-handler/update-page-title! route))))
-     [nfs-granted? db-restoring? route])
+     [db-restoring? route])
 
 
     (hooks/use-effect!
     (hooks/use-effect!
      (fn []
      (fn []

+ 31 - 21
src/main/frontend/components/views.cljs

@@ -406,7 +406,7 @@
     columns))
     columns))
 
 
 (rum/defc more-actions
 (rum/defc more-actions
-  [view-entity columns {:keys [column-visible? rows column-toggle-visibility]}]
+  [view-entity columns {:keys [column-visible? rows column-toggle-visibility]} {:keys [group-by-property-ident]}]
   (let [display-type (:db/ident (:logseq.property.view/type view-entity))
   (let [display-type (:db/ident (:logseq.property.view/type view-entity))
         table? (= display-type :logseq.property.view/type.table)
         table? (= display-type :logseq.property.view/type.table)
         group-by-columns (concat (when (or
         group-by-columns (concat (when (or
@@ -455,7 +455,7 @@
              (shui/dropdown-menu-checkbox-item
              (shui/dropdown-menu-checkbox-item
               {:key (str (:id column))
               {:key (str (:id column))
                :className "capitalize"
                :className "capitalize"
-               :checked (= (:id column) (:db/ident (:logseq.property.view/group-by-property view-entity)))
+               :checked (= (:id column) group-by-property-ident)
                :onCheckedChange (fn [result]
                :onCheckedChange (fn [result]
                                   (if result
                                   (if result
                                     (db-property-handler/set-block-property! (:db/id view-entity) :logseq.property.view/group-by-property
                                     (db-property-handler/set-block-property! (:db/id view-entity) :logseq.property.view/group-by-property
@@ -1828,12 +1828,12 @@
         [:div.text-muted-foreground.text-sm
         [:div.text-muted-foreground.text-sm
          (pv/property-value view-entity (db/entity :logseq.property.view/type) {})])
          (pv/property-value view-entity (db/entity :logseq.property.view/type) {})])
 
 
-      (when db-based? (more-actions view-entity columns table))
+      (when db-based? (more-actions view-entity columns table option))
 
 
       (when (and db-based? add-new-object!) (new-record-button table view-entity))]]))
       (when (and db-based? add-new-object!) (new-record-button table view-entity))]]))
 
 
 (rum/defc ^:large-vars/cleanup-todo view-inner < rum/static
 (rum/defc ^:large-vars/cleanup-todo view-inner < rum/static
-  [view-entity {:keys [view-parent data full-data set-data! columns add-new-object! foldable-options input set-input! sorting set-sorting! filters set-filters! view-feature-type] :as option*}
+  [view-entity {:keys [view-parent data full-data set-data! columns add-new-object! foldable-options input set-input! sorting set-sorting! filters set-filters! display-type group-by-property-ident] :as option*}
    *scroller-ref]
    *scroller-ref]
   (let [db-based? (config/db-based-graph?)
   (let [db-based? (config/db-based-graph?)
         option (assoc option* :properties
         option (assoc option* :properties
@@ -1875,7 +1875,8 @@
                                                (remove (fn [column]
                                                (remove (fn [column]
                                                          (false? (get visible-columns (:id column))))
                                                          (false? (get visible-columns (:id column))))
                                                        columns))
                                                        columns))
-        group-by-property (:logseq.property.view/group-by-property view-entity)
+        group-by-property (or (:logseq.property.view/group-by-property view-entity)
+                              (db/entity group-by-property-ident))
         table-map {:view-entity view-entity
         table-map {:view-entity view-entity
                    :data data
                    :data data
                    :full-data full-data
                    :full-data full-data
@@ -1901,21 +1902,8 @@
                               :set-last-selected-idx! set-last-selected-idx!}}
                               :set-last-selected-idx! set-last-selected-idx!}}
         table (shui/table-option table-map)
         table (shui/table-option table-map)
         *view-ref (rum/use-ref nil)
         *view-ref (rum/use-ref nil)
-        display-type (if (config/db-based-graph?)
-                       (or (:db/ident (get view-entity :logseq.property.view/type))
-                           (when (= (:view-type option) :linked-references)
-                             :logseq.property.view/type.list)
-                           :logseq.property.view/type.table)
-                       (if (= view-feature-type :all-pages)
-                         :logseq.property.view/type.table
-                         :logseq.property.view/type.list))
         gallery? (= display-type :logseq.property.view/type.gallery)
         gallery? (= display-type :logseq.property.view/type.gallery)
-        list-view? (= display-type :logseq.property.view/type.list)
-        group-by-property-ident (or (:db/ident group-by-property)
-                                    (when (and list-view? (nil? group-by-property))
-                                      :block/page)
-                                    (when (and (not db-based?) (contains? #{:linked-references :unlinked-references} view-feature-type))
-                                      :block/page))]
+        list-view? (= display-type :logseq.property.view/type.list)]
 
 
     (run-effects! option table-map *scroller-ref gallery?)
     (run-effects! option table-map *scroller-ref gallery?)
 
 
@@ -1954,6 +1942,7 @@
                    (rum/with-key
                    (rum/with-key
                      (ui/foldable
                      (ui/foldable
                       [:div
                       [:div
+                       {:class (when-not list-view? "my-4")}
                        (cond
                        (cond
                          group-by-page?
                          group-by-page?
                          (if value
                          (if value
@@ -1974,7 +1963,9 @@
                       {:title-trigger? false})
                       {:title-trigger? false})
                      (str (:db/id view-entity) "-group-idx-" idx))))
                      (str (:db/id view-entity) "-group-idx-" idx))))
                (:rows table))])
                (:rows table))])
-           (view-cp view-entity table option view-opts)))]
+           (view-cp view-entity table
+                    (assoc option :group-by-property-ident group-by-property-ident)
+                    view-opts)))]
       (merge {:title-trigger? false} foldable-options))]))
       (merge {:title-trigger? false} foldable-options))]))
 
 
 (rum/defcs view-container
 (rum/defcs view-container
@@ -2005,6 +1996,22 @@
 (rum/defc view-aux
 (rum/defc view-aux
   [view-entity {:keys [view-parent view-feature-type data query-entity-ids set-view-entity!] :as option}]
   [view-entity {:keys [view-parent view-feature-type data query-entity-ids set-view-entity!] :as option}]
   (let [[input set-input!] (hooks/use-state "")
   (let [[input set-input!] (hooks/use-state "")
+        db-based? (config/db-based-graph?)
+        group-by-property (:logseq.property.view/group-by-property view-entity)
+        display-type (if (config/db-based-graph?)
+                       (or (:db/ident (get view-entity :logseq.property.view/type))
+                           (when (= (:view-type option) :linked-references)
+                             :logseq.property.view/type.list)
+                           :logseq.property.view/type.table)
+                       (if (= view-feature-type :all-pages)
+                         :logseq.property.view/type.table
+                         :logseq.property.view/type.list))
+        list-view? (= display-type :logseq.property.view/type.list)
+        group-by-property-ident (or (:db/ident group-by-property)
+                                    (when (and list-view? (nil? group-by-property))
+                                      :block/page)
+                                    (when (and (not db-based?) (contains? #{:linked-references :unlinked-references} view-feature-type))
+                                      :block/page))
         sorting* (:logseq.property.table/sorting view-entity)
         sorting* (:logseq.property.table/sorting view-entity)
         sorting (if (or (= sorting* :logseq.property/empty-placeholder) (empty? sorting*))
         sorting (if (or (= sorting* :logseq.property/empty-placeholder) (empty? sorting*))
                   [{:id :block/updated-at, :asc? false}]
                   [{:id :block/updated-at, :asc? false}]
@@ -2035,6 +2042,7 @@
                                                              {:view-for-id (or (:db/id (:logseq.property/view-for view-entity))
                                                              {:view-for-id (or (:db/id (:logseq.property/view-for view-entity))
                                                                                (:db/id view-parent))
                                                                                (:db/id view-parent))
                                                               :view-feature-type view-feature-type
                                                               :view-feature-type view-feature-type
+                                                              :group-by-property-ident group-by-property-ident
                                                               :input input
                                                               :input input
                                                               :filters filters
                                                               :filters filters
                                                               :sorting sorting}
                                                               :sorting sorting}
@@ -2052,7 +2060,7 @@
        [(:db/id view-entity)
        [(:db/id view-entity)
         (hooks/use-debounced-value input 300)
         (hooks/use-debounced-value input 300)
         sorting-filters
         sorting-filters
-        (:db/id (:logseq.property.view/group-by-property view-entity))
+        group-by-property-ident
         (:db/id (:logseq.property.view/type view-entity))
         (:db/id (:logseq.property.view/type view-entity))
         ;; page filters
         ;; page filters
         (:logseq.property.linked-references/includes view-parent)
         (:logseq.property.linked-references/includes view-parent)
@@ -2079,7 +2087,9 @@
                                                          ;; grouped
                                                          ;; grouped
                                                          (reduce (fn [total [_ col]]
                                                          (reduce (fn [total [_ col]]
                                                                    (+ total (count col))) 0 data))
                                                                    (+ total (count col))) 0 data))
+                                          :group-by-property-ident group-by-property-ident
                                           :ref-pages-count ref-pages-count
                                           :ref-pages-count ref-pages-count
+                                          :display-type display-type
                                           :load-view-data load-view-data
                                           :load-view-data load-view-data
                                           :set-view-entity! set-view-entity!))])))
                                           :set-view-entity! set-view-entity!))])))
 
 

+ 6 - 16
src/main/frontend/db/persist.cljs

@@ -1,13 +1,13 @@
 (ns frontend.db.persist
 (ns frontend.db.persist
   "Handles operations to persisting db to disk or indexedDB"
   "Handles operations to persisting db to disk or indexedDB"
-  (:require [frontend.util :as util]
-            [frontend.idb :as idb]
+  (:require [cljs-bean.core :as bean]
             [electron.ipc :as ipc]
             [electron.ipc :as ipc]
+            [frontend.config :as config]
             [frontend.db.conn :as db-conn]
             [frontend.db.conn :as db-conn]
-            [promesa.core :as p]
+            [frontend.idb :as idb]
             [frontend.persist-db :as persist-db]
             [frontend.persist-db :as persist-db]
-            [cljs-bean.core :as bean]
-            [frontend.config :as config]))
+            [frontend.util :as util]
+            [promesa.core :as p]))
 
 
 (defn get-all-graphs
 (defn get-all-graphs
   []
   []
@@ -24,7 +24,7 @@
     (distinct (concat
     (distinct (concat
                repos'
                repos'
                (map (fn [repo-name] {:name repo-name})
                (map (fn [repo-name] {:name repo-name})
-                 (concat idb-repos (some-> electron-disk-graphs bean/->clj)))))))
+                    (concat idb-repos (some-> electron-disk-graphs bean/->clj)))))))
 
 
 (defn delete-graph!
 (defn delete-graph!
   [graph]
   [graph]
@@ -34,13 +34,3 @@
       (if (util/electron?)
       (if (util/electron?)
         (ipc/ipc "deleteGraph" graph key db-based?)
         (ipc/ipc "deleteGraph" graph key db-based?)
         (idb/remove-item! key)))))
         (idb/remove-item! key)))))
-
-(defn rename-graph!
-  [old-repo new-repo]
-  (let [old-key (db-conn/get-repo-path old-repo)
-        new-key (db-conn/get-repo-path new-repo)]
-    (if (util/electron?)
-      (do
-        (js/console.error "rename-graph! is not supported in electron")
-        (idb/rename-item! old-key new-key))
-      (idb/rename-item! old-key new-key))))

+ 7 - 28
src/main/frontend/encrypt.cljs

@@ -1,41 +1,20 @@
 (ns frontend.encrypt
 (ns frontend.encrypt
   "Encryption related fns for use with encryption feature and file sync"
   "Encryption related fns for use with encryption feature and file sync"
-  (:require [logseq.graph-parser.utf8 :as utf8]
+  (:require [electron.ipc :as ipc]
             [frontend.util :as util]
             [frontend.util :as util]
-            [promesa.core :as p]
-            [electron.ipc :as ipc]
-            [frontend.mobile.util :as mobile-util]))
+            [logseq.graph-parser.utf8 :as utf8]
+            [promesa.core :as p]))
 
 
 (defn encrypt-with-passphrase
 (defn encrypt-with-passphrase
   [passphrase content]
   [passphrase content]
-  (cond
-    (util/electron?)
+  (when (util/electron?)
     (p/let [raw-content (utf8/encode content)
     (p/let [raw-content (utf8/encode content)
             encrypted (ipc/ipc "encrypt-with-passphrase" passphrase raw-content)]
             encrypted (ipc/ipc "encrypt-with-passphrase" passphrase raw-content)]
-      (utf8/decode encrypted))
-
-    (mobile-util/native-platform?)
-    (p/chain (.encryptWithPassphrase mobile-util/file-sync
-                                     (clj->js {:passphrase passphrase :content content}))
-             #(js->clj % :keywordize-keys true)
-             :data)
-
-    :else
-    nil))
+      (utf8/decode encrypted))))
 
 
 (defn decrypt-with-passphrase
 (defn decrypt-with-passphrase
   [passphrase content]
   [passphrase content]
-  (cond
-    (util/electron?)
+  (when (util/electron?)
     (p/let [raw-content (utf8/encode content)
     (p/let [raw-content (utf8/encode content)
             decrypted (ipc/ipc "decrypt-with-passphrase" passphrase raw-content)]
             decrypted (ipc/ipc "decrypt-with-passphrase" passphrase raw-content)]
-      (utf8/decode decrypted))
-
-    (mobile-util/native-platform?)
-    (p/chain (.decryptWithPassphrase mobile-util/file-sync
-                                     (clj->js {:passphrase passphrase :content content}))
-             #(js->clj % :keywordize-keys true)
-             :data)
-
-    :else
-    nil))
+      (utf8/decode decrypted))))

+ 20 - 23
src/main/frontend/extensions/excalidraw.cljs

@@ -1,22 +1,22 @@
 (ns frontend.extensions.excalidraw
 (ns frontend.extensions.excalidraw
-  (:require [clojure.string :as string]
-            ;; NOTE: Always use production build of excalidraw
+  (:require ;; NOTE: Always use production build of excalidraw
             ;; See-also: https://github.com/excalidraw/excalidraw/pull/3330
             ;; See-also: https://github.com/excalidraw/excalidraw/pull/3330
-            ["@excalidraw/excalidraw/dist/excalidraw.production.min" :refer [Excalidraw serializeAsJSON]]
-            [frontend.config :as config]
-            [frontend.db :as db]
-            [frontend.handler.editor :as editor-handler]
-            [frontend.handler.draw :as draw]
-            [frontend.handler.notification :as notification]
-            [frontend.handler.ui :as ui-handler]
-            [frontend.rum :as r]
-            [frontend.state :as state]
-            [frontend.ui :as ui]
-            [frontend.util :as util]
-            [goog.object :as gobj]
-            [goog.functions :refer [debounce]]
-            [rum.core :as rum]
-            [frontend.mobile.util :as mobile-util]))
+   ["@excalidraw/excalidraw/dist/excalidraw.production.min" :refer [Excalidraw serializeAsJSON]]
+   [clojure.string :as string]
+   [frontend.config :as config]
+   [frontend.db :as db]
+   [frontend.handler.draw :as draw]
+   [frontend.handler.editor :as editor-handler]
+   [frontend.handler.notification :as notification]
+   [frontend.handler.ui :as ui-handler]
+   [frontend.mobile.util :as mobile-util]
+   [frontend.rum :as r]
+   [frontend.state :as state]
+   [frontend.ui :as ui]
+   [frontend.util :as util]
+   [goog.functions :refer [debounce]]
+   [goog.object :as gobj]
+   [rum.core :as rum]))
 
 
 (def excalidraw (r/adapt-class Excalidraw))
 (def excalidraw (r/adapt-class Excalidraw))
 
 
@@ -99,8 +99,8 @@
        [:div.draw-wrap
        [:div.draw-wrap
         {:ref ref
         {:ref ref
          :on-pointer-down (fn [e]
          :on-pointer-down (fn [e]
-                          (util/stop e)
-                          (state/set-block-component-editing-mode! true))
+                            (util/stop e)
+                            (state/set-block-component-editing-mode! true))
          :on-blur #(state/set-block-component-editing-mode! false)
          :on-blur #(state/set-block-component-editing-mode! false)
          :style {:width  @*draw-width
          :style {:width  @*draw-width
                  :height (if wide-mode? 650 500)}}
                  :height (if wide-mode? 650 500)}}
@@ -162,11 +162,8 @@
 
 
 (rum/defc draw < rum/reactive
 (rum/defc draw < rum/reactive
   [option]
   [option]
-  (let [repo (state/get-current-repo)
-        granted? (state/sub [:nfs/user-granted? repo])]
-    ;; Web granted
+  (let [repo (state/get-current-repo)]
     (when-not (and (config/local-file-based-graph? repo)
     (when-not (and (config/local-file-based-graph? repo)
-                   (not granted?)
                    (not (util/electron?))
                    (not (util/electron?))
                    (not (mobile-util/native-platform?)))
                    (not (mobile-util/native-platform?)))
       (draw-container option))))
       (draw-container option))))

+ 6 - 5
src/main/frontend/extensions/pdf/assets.cljs

@@ -19,7 +19,7 @@
             [frontend.handler.property :as property-handler]
             [frontend.handler.property :as property-handler]
             [frontend.handler.property.util :as pu]
             [frontend.handler.property.util :as pu]
             [frontend.handler.route :as route-handler]
             [frontend.handler.route :as route-handler]
-            [frontend.ref :as ref]
+            [frontend.util.ref :as ref]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.ui :as ui]
             [frontend.util :as util]
             [frontend.util :as util]
@@ -49,8 +49,9 @@
         url       (if blob-res? href
         url       (if blob-res? href
                       (assets-handler/normalize-asset-resource-url original-path))
                       (assets-handler/normalize-asset-resource-url original-path))
         filename' (if (or asset-res? web-link? blob-res?) filename
         filename' (if (or asset-res? web-link? blob-res?) filename
-                      (some-> (get-in-repo-assets-full-filename url)
-                              (js/decodeURIComponent) (string/replace '"/" "_")))
+                    (some-> url (js/decodeURIComponent)
+                      (get-in-repo-assets-full-filename)
+                      (string/replace '"/" "_")))
         filekey   (util/safe-sanitize-file-name
         filekey   (util/safe-sanitize-file-name
                    (subs filename' 0 (- (count filename') (inc (count ext-name)))))]
                    (subs filename' 0 (- (count filename') (inc (count ext-name)))))]
     (when-let [key (and (not (string/blank? filekey))
     (when-let [key (and (not (string/blank? filekey))
@@ -216,7 +217,7 @@
     (let [repo-cur (state/get-current-repo)
     (let [repo-cur (state/get-current-repo)
           repo-dir (config/get-repo-dir repo-cur)
           repo-dir (config/get-repo-dir repo-cur)
           data     (with-out-str (pprint {:highlights highlights :extra extra}))]
           data     (with-out-str (pprint {:highlights highlights :extra extra}))]
-      (fs/write-file! repo-cur repo-dir hls-file data {:skip-compare? true}))))
+      (fs/write-plain-text-file! repo-cur repo-dir hls-file data {:skip-compare? true}))))
 
 
 (defn file-based-resolve-hls-data-by-key$
 (defn file-based-resolve-hls-data-by-key$
   [target-key]
   [target-key]
@@ -242,7 +243,7 @@
           new-fpath  (str fdir "/" fname "_" fstamp ".png")
           new-fpath  (str fdir "/" fname "_" fstamp ".png")
           old-fpath  (and old-fstamp (str fdir "/" fname "_" old-fstamp ".png"))
           old-fpath  (and old-fstamp (str fdir "/" fname "_" old-fstamp ".png"))
           _          (and old-fpath (fs/rename! repo-url old-fpath new-fpath))
           _          (and old-fpath (fs/rename! repo-url old-fpath new-fpath))
-          _          (fs/write-file! repo-url repo-dir new-fpath png {:skip-compare? true})]
+          _          (fs/write-plain-text-file! repo-url repo-dir new-fpath png {:skip-compare? true})]
 
 
     (js/console.timeEnd :write-area-image)))
     (js/console.timeEnd :write-area-image)))
 
 

+ 1 - 1
src/main/frontend/extensions/zotero/handler.cljs

@@ -9,7 +9,7 @@
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
             [frontend.handler.page :as page-handler]
             [frontend.handler.page :as page-handler]
-            [frontend.ref :as ref]
+            [frontend.util.ref :as ref]
             [frontend.state :as state]
             [frontend.state :as state]
             [promesa.core :as p]))
             [promesa.core :as p]))
 
 

+ 1 - 2
src/main/frontend/flows.cljs

@@ -46,5 +46,4 @@
        (m/relieve)))
        (m/relieve)))
 
 
 (def network-online-event-flow
 (def network-online-event-flow
-  (->> (m/watch *network-online?)
-       (m/eduction (filter true?))))
+  (m/watch *network-online?))

+ 14 - 41
src/main/frontend/fs.cljs

@@ -2,39 +2,27 @@
   "System-component-like ns that provides common file operations for all
   "System-component-like ns that provides common file operations for all
   platforms by delegating to implementations of the fs protocol"
   platforms by delegating to implementations of the fs protocol"
   (:require [cljs-bean.core :as bean]
   (:require [cljs-bean.core :as bean]
+            [clojure.string :as string]
+            [electron.ipc :as ipc]
             [frontend.config :as config]
             [frontend.config :as config]
-            [frontend.fs.nfs :as nfs]
-            [frontend.fs.node :as node]
-            [frontend.fs.capacitor-fs :as capacitor-fs]
             [frontend.fs.memory-fs :as memory-fs]
             [frontend.fs.memory-fs :as memory-fs]
-            [frontend.mobile.util :as mobile-util]
+            [frontend.fs.node :as node]
             [frontend.fs.protocol :as protocol]
             [frontend.fs.protocol :as protocol]
+            [frontend.state :as state]
             [frontend.util :as util]
             [frontend.util :as util]
             [lambdaisland.glogi :as log]
             [lambdaisland.glogi :as log]
-            [promesa.core :as p]
             [logseq.common.path :as path]
             [logseq.common.path :as path]
-            [clojure.string :as string]
-            [frontend.state :as state]
             [logseq.common.util :as common-util]
             [logseq.common.util :as common-util]
-            [electron.ipc :as ipc]))
+            [promesa.core :as p]))
 
 
-(defonce nfs-backend (nfs/->Nfs))
 (defonce memory-backend (memory-fs/->MemoryFs))
 (defonce memory-backend (memory-fs/->MemoryFs))
 (defonce node-backend (node/->Node))
 (defonce node-backend (node/->Node))
-(defonce mobile-backend (capacitor-fs/->Capacitorfs))
 
 
 (defn- get-native-backend
 (defn- get-native-backend
   "Native FS backend of current platform"
   "Native FS backend of current platform"
   []
   []
-  (cond
-    (util/electron?)
-    node-backend
-
-    (mobile-util/native-platform?)
-    mobile-backend
-
-    :else
-    nfs-backend))
+  (when (util/electron?)
+    node-backend))
 
 
 (defn get-fs
 (defn get-fs
   [dir & {:keys [repo rpath]}]
   [dir & {:keys [repo rpath]}]
@@ -62,11 +50,8 @@
       (and (util/electron?) (not bfs-local?))
       (and (util/electron?) (not bfs-local?))
       node-backend
       node-backend
 
 
-      (mobile-util/native-platform?)
-      mobile-backend
-
       :else
       :else
-      nfs-backend)))
+      nil)))
 
 
 (defn mkdir!
 (defn mkdir!
   [dir]
   [dir]
@@ -99,8 +84,8 @@
     (when (= fs memory-backend)
     (when (= fs memory-backend)
       (protocol/rmdir! fs dir))))
       (protocol/rmdir! fs dir))))
 
 
-;; TODO(andelf): distinguish from graph file writing and global file write
-(defn write-file!
+(defn write-plain-text-file!
+  "Use it only for plain-text files, not binary"
   [repo dir rpath content opts]
   [repo dir rpath content opts]
   (when content
   (when content
     (let [path (common-util/path-normalize rpath)
     (let [path (common-util/path-normalize rpath)
@@ -174,7 +159,7 @@
 
 
     :else
     :else
     (let [[old-path new-path]
     (let [[old-path new-path]
-          (map #(if (or (util/electron?) (mobile-util/native-platform?))
+          (map #(if (util/electron?)
                   %
                   %
                   (str (config/get-repo-dir repo) "/" %))
                   (str (config/get-repo-dir repo) "/" %))
                [old-path new-path])
                [old-path new-path])
@@ -182,8 +167,6 @@
       (p/let [_ (mkdir-if-not-exists new-dir)]
       (p/let [_ (mkdir-if-not-exists new-dir)]
         (protocol/copy! (get-fs old-path) repo old-path new-path)))))
         (protocol/copy! (get-fs old-path) repo old-path new-path)))))
 
 
-
-
 (defn open-dir
 (defn open-dir
   [dir]
   [dir]
   (let [record (get-native-backend)]
   (let [record (get-native-backend)]
@@ -227,7 +210,7 @@
          true)
          true)
        (p/catch
        (p/catch
         (fn [_error]
         (fn [_error]
-          (p/let [_ (write-file! repo dir path initial-content nil)]
+          (p/let [_ (write-plain-text-file! repo dir path initial-content nil)]
             false))))))
             false))))))
 
 
 (defn file-exists?
 (defn file-exists?
@@ -256,9 +239,6 @@
     (util/electron?)
     (util/electron?)
     (path/url-to-path path)
     (path/url-to-path path)
 
 
-    (mobile-util/native-platform?)
-    path
-
     :else
     :else
     path))
     path))
 
 
@@ -268,12 +248,5 @@
 
 
 (defn backup-db-file!
 (defn backup-db-file!
   [repo path db-content disk-content]
   [repo path db-content disk-content]
-  (cond
-    (util/electron?)
-    (ipc/ipc "backupDbFile" (config/get-local-dir repo) path db-content disk-content)
-
-    (mobile-util/native-platform?)
-    (capacitor-fs/backup-file repo :backup-dir path db-content)
-
-    ;; TODO: nfs
-    ))
+  (when (util/electron?)
+    (ipc/ipc "backupDbFile" (config/get-local-dir repo) path db-content disk-content)))

+ 0 - 404
src/main/frontend/fs/capacitor_fs.cljs

@@ -1,404 +0,0 @@
-(ns frontend.fs.capacitor-fs
-  "Implementation of fs protocol for mobile"
-  (:require ["@capacitor/filesystem" :refer [Encoding Filesystem]]
-            [cljs-bean.core :as bean]
-            [clojure.string :as string]
-            [goog.string :as gstring]
-            [frontend.config :as config]
-            [frontend.db :as db]
-            [frontend.fs.protocol :as protocol]
-            [frontend.mobile.util :as mobile-util]
-            [frontend.state :as state]
-            [frontend.util :as util]
-            [lambdaisland.glogi :as log]
-            [promesa.core :as p]
-            [rum.core :as rum]
-            [logseq.common.path :as path]))
-
-(when (mobile-util/native-ios?)
-  (defn ios-ensure-documents!
-    []
-    (.ensureDocuments mobile-util/ios-file-container)))
-
-(when (mobile-util/native-android?)
-  (defn- android-check-permission []
-    (p/let [permission (.checkPermissions Filesystem)
-            permission (-> permission
-                           bean/->clj
-                           :publicStorage)]
-      (when-not (= permission "granted")
-        (p/do!
-         (.requestPermissions Filesystem))))))
-
-(defn- <dir-exists?
-  [fpath]
-  (p/catch (p/let [fpath (path/path-normalize fpath)
-                   stat (.stat Filesystem (clj->js {:path fpath}))]
-             (-> stat
-                 bean/->clj
-                 :type
-                 (= "directory")))
-           (fn [_error]
-             false)))
-
-(defn <write-file-with-base64
-  "Write a binary file, requires base64 encoding"
-  [path content]
-  (when-not (string/blank? path)
-    (-> (p/chain (.writeFile Filesystem (clj->js {:path path
-                                                  :data content
-                                                  :recursive true}))
-                 #(js->clj % :keywordize-keys true))
-        (p/catch (fn [error]
-                   (js/console.error "writeFile Error: " path ": " error)
-                   nil)))))
-
-(defn- <write-file-with-utf8
-  [path content]
-  (when-not (string/blank? path)
-    (-> (p/chain (.writeFile Filesystem (clj->js {:path path
-                                                  :data content
-                                                  :encoding (.-UTF8 Encoding)
-                                                  :recursive true}))
-                 #(js->clj % :keywordize-keys true))
-        (p/catch (fn [error]
-                   (js/console.error "writeFile Error: " path ": " error)
-                   nil)))))
-
-(defn- <read-file-with-utf8
-  [path]
-  (when-not (string/blank? path)
-    (-> (p/chain (.readFile Filesystem (clj->js {:path path
-                                                 :encoding (.-UTF8 Encoding)}))
-                 #(js->clj % :keywordize-keys true)
-                 #(get % :data nil))
-        (p/catch (fn [error]
-                   (js/console.error "readFile Error: " path ": " error)
-                   nil)))))
-
-(defn- <readdir [path]
-  (-> (p/chain (.readdir Filesystem (clj->js {:path path}))
-               #(js->clj % :keywordize-keys true)
-               :files)
-      (p/catch (fn [error]
-                 (js/console.error "readdir Error: " path ": " error)
-                 nil))))
-
-(defn- get-file-paths
-  "get all file paths recursively"
-  [path]
-  (p/let [result (p/loop [result []
-                          dirs [path]]
-                   (if (empty? dirs)
-                     result
-                     (p/let [d (first dirs)
-                             files (<readdir d)
-                             files (->> files
-                                        (remove (fn [{:keys [name  type]}]
-                                                  (or (string/starts-with? name ".")
-                                                      (and (= type "directory")
-                                                           (or (= name "bak")
-                                                               (= name "version-files")))))))
-                             files-dir (->> files
-                                            (filterv #(= (:type %) "directory"))
-                                            (mapv :uri))
-                             paths-result (->> files
-                                               (filterv #(= (:type %) "file"))
-                                               (mapv :uri))]
-                       (p/recur (concat result paths-result)
-                                (concat (rest dirs) files-dir)))))]
-    result))
-
-(defn- get-files
-  "get all files and contents recursively"
-  [path]
-  (p/let [result (p/loop [result []
-                          dirs [path]]
-                   (if (empty? dirs)
-                     result
-                     (p/let [d (first dirs)
-                             files (<readdir d)
-                             files (->> files
-                                        (remove (fn [{:keys [name  type]}]
-                                                  (or (string/starts-with? name ".")
-                                                      (and (= type "directory")
-                                                           (or (= name "bak")
-                                                               (= name "version-files")))))))
-                             files-dir (->> files
-                                            (filterv #(= (:type %) "directory"))
-                                            (mapv :uri))
-                             files-result
-                             (p/all
-                              (->> files
-                                   (filter #(= (:type %) "file"))
-                                   (filter
-                                    (fn [{:keys [uri]}]
-                                      (some #(string/ends-with? uri %)
-                                            [".md" ".markdown" ".org" ".edn" ".css"])))
-                                   (mapv
-                                    (fn [{:keys [uri] :as file-info}]
-                                      (p/chain (<read-file-with-utf8 uri)
-                                               #(assoc (dissoc file-info :uri)
-                                                       :content %
-                                                       :path uri))))))]
-                       (p/recur (concat result files-result)
-                                (concat (rest dirs) files-dir)))))]
-    (js->clj result :keywordize-keys true)))
-
-(defn- <contents-matched?
-  [disk-content db-content]
-  (when (and (string? disk-content) (string? db-content))
-    (p/resolved (= (string/trim disk-content) (string/trim db-content)))))
-
-(def backup-dir "logseq/bak")
-(def version-file-dir "logseq/version-files/local")
-
-(defn- get-backup-dir
-  [repo-dir path bak-dir ext]
-  (let [relative-path (-> path
-                          (string/replace (re-pattern (str "^" (gstring/regExpEscape repo-dir)))
-                                          "")
-                          (string/replace (re-pattern (str "(?i)" (gstring/regExpEscape (str "." ext)) "$"))
-                                          ""))]
-    (path/path-join repo-dir bak-dir relative-path)))
-
-(defn- <truncate-old-versioned-files!
-  "reserve the latest 6 version files"
-  [dir]
-  (-> (p/let [files (.readdir Filesystem (clj->js {:path dir}))
-
-              files (:files (js->clj files :keywordize-keys true))]
-        (drop 6 (reverse (sort-by :mtime files))))
-      (p/then (fn [old-version-files]
-                (p/all (mapv (fn [file]
-                               (.deleteFile Filesystem (clj->js {:path (:uri file)})))
-                             old-version-files))))
-      (p/catch (fn [_]))))
-
-;; TODO: move this to FS protocol
-(defn backup-file
-  "backup CONTENT under DIR :backup-dir or :version-file-dir
-  :backup-dir = `backup-dir`
-  :version-file-dir = `version-file-dir`"
-  [repo dir path content]
-  {:pre [(contains? #{:backup-dir :version-file-dir} dir)]}
-  (let [repo-dir (config/get-local-dir repo)
-        ext (util/get-file-ext path)
-        dir (case dir
-              :backup-dir (get-backup-dir repo-dir path backup-dir ext)
-              :version-file-dir (get-backup-dir repo-dir path version-file-dir ext))
-        new-path (path/path-join dir (str (string/replace (.toISOString (js/Date.)) ":" "_") "." (mobile-util/platform) "." ext))]
-
-    (<write-file-with-utf8 new-path content)
-    (<truncate-old-versioned-files! dir)))
-
-(defn backup-file-handle-changed!
-  [repo-dir file-path content]
-  (let [divider-schema    "://"
-        file-schema       (string/split file-path divider-schema)
-        file-schema       (if (> (count file-schema) 1) (first file-schema) "")
-        dir-schema?       (and (string? repo-dir)
-                               (string/includes? repo-dir divider-schema))
-        repo-dir          (if-not dir-schema?
-                            (str file-schema divider-schema repo-dir) repo-dir)
-        backup-root       (path/path-join repo-dir backup-dir)
-        backup-dir-parent (util/node-path.dirname file-path)
-        backup-dir-parent (string/replace backup-dir-parent repo-dir "")
-        backup-dir-name (util/node-path.name file-path)
-        file-extname (.extname util/node-path file-path)
-        file-root (path/path-join backup-root backup-dir-parent backup-dir-name)
-        file-path (path/path-join file-root
-                                  (str (string/replace (.toISOString (js/Date.)) ":" "_") "." (mobile-util/platform) file-extname))]
-    (<write-file-with-utf8 file-path content)
-    (<truncate-old-versioned-files! file-root)))
-
-(defn- write-file-impl!
-  [repo dir rpath content {:keys [ok-handler error-handler old-content skip-compare?]} stat]
-  (let [fpath (path/path-join dir rpath)]
-    (if (or (string/blank? repo) skip-compare?)
-      (p/catch
-       (p/let [result (<write-file-with-utf8 fpath content)]
-         (when ok-handler
-           (ok-handler repo fpath result)))
-       (fn [error]
-         (if error-handler
-           (error-handler error)
-           (log/error :write-file-failed error))))
-
-    ;; Compare with disk content and backup if not equal
-      (p/let [disk-content (if (not= stat :not-found)
-                             (<read-file-with-utf8 fpath)
-                             "")
-              disk-content (or disk-content "")
-              repo-dir (config/get-local-dir repo)
-              db-content (or old-content (db/get-file repo rpath) "")
-              contents-matched? (<contents-matched? disk-content db-content)]
-        (->
-         (p/let [result (<write-file-with-utf8 fpath content)
-                 mtime (-> (js->clj stat :keywordize-keys true)
-                           :mtime)]
-           (when-not contents-matched?
-             (backup-file repo-dir :backup-dir fpath disk-content))
-           (db/set-file-last-modified-at! repo rpath mtime)
-           (db/set-file-content! repo rpath content)
-           (when ok-handler
-             (ok-handler repo fpath result))
-           result)
-         (p/catch (fn [error]
-                    (if error-handler
-                      (error-handler error)
-                      (log/error :write-file-failed error)))))))))
-
-(defn ios-force-include-private
-  "iOS sometimes return paths without the private part."
-  [path]
-  (if (mobile-util/native-ios?)
-    (cond
-      (or (string/includes? path "///private/")
-          ;; virtual machine
-          (string/starts-with? path "file:///Users/"))
-      path
-
-      (string/includes? path "///")
-      (let [[prefix others] (string/split path "///")]
-        (str prefix "///private/" others))
-
-      :else
-      path)
-    path))
-
-(defn- local-container-path?
-  "Check whether `path' is logseq's container `localDocumentsPath' on iOS"
-  [path localDocumentsPath]
-  (string/includes? path localDocumentsPath))
-
-(rum/defc instruction
-  []
-  [:div.instruction
-   [:h1.title "Please choose a valid directory!"]
-   [:p.leading-6 "Logseq app can only save or access your graphs stored in a specific directory with a "
-    [:strong "Logseq icon"]
-    " inside, located either in \"iCloud Drive\", \"On My iPhone\" or \"On My iPad\"."]
-   [:p.leading-6 "Please watch the following short instruction video. "
-    [:small.text-gray-500 "(may take few seconds to load...)"]]
-   [:iframe
-    {:src "https://www.loom.com/embed/dae612ae5fd94e508bd0acdf02efb888"
-     :frame-border "0"
-     :position "relative"
-     :allow-full-screen "allowfullscreen"
-     :webkit-allow-full-screen "webkitallowfullscreen"
-     :height "100%"}]])
-
-(defn- open-dir
-  [dir]
-  (p/let [_ (when (mobile-util/native-android?) (android-check-permission))
-          {:keys [path localDocumentsPath]} (-> (.pickFolder mobile-util/folder-picker
-                                                             (clj->js (when (and dir (mobile-util/native-ios?))
-                                                                        {:path dir})))
-                                                (p/then #(js->clj % :keywordize-keys true))
-                                                (p/catch (fn [e]
-                                                           (js/alert (str e))
-                                                           nil))) ;; NOTE: If pick folder fails, let it crash
-          _ (when (and (mobile-util/native-ios?)
-                       (not (or (local-container-path? path localDocumentsPath)
-                                (mobile-util/in-iCloud-container-path? path))))
-              (state/pub-event! [:modal/show-instruction]))
-          exists? (<dir-exists? path)
-          _ (when-not exists?
-              (p/rejected (str "Cannot access selected directory: " path)))
-          _ (when (mobile-util/is-iCloud-container-path? path)
-              (p/rejected (str "Please avoid accessing the top-level iCloud container path: " path)))
-          path (if (mobile-util/native-ios?)
-                 (ios-force-include-private path)
-                 path)
-          _ (js/console.log "Opening or Creating graph at directory: " path)
-          files (get-files path)]
-    {:path path
-     :files (into [] files)}))
-
-(defrecord ^:large-vars/cleanup-todo Capacitorfs []
-  protocol/Fs
-  (mkdir! [_this dir]
-    (-> (<dir-exists? dir)
-        (p/then (fn [exists?]
-                  (if exists?
-                    (p/resolved true)
-                    (.mkdir Filesystem
-                            (clj->js
-                             {:path dir})))))
-        (p/catch (fn [error]
-                   (log/error :mkdir! {:path dir
-                                       :error error})))))
-  (mkdir-recur! [_this dir]
-    (-> (<dir-exists? dir)
-        (p/then (fn [exists?]
-                  (if exists?
-                    (p/resolved true)
-                    (.mkdir Filesystem
-                            (clj->js
-                             {:path dir
-                              :recursive true})))))
-        (p/catch (fn [error]
-                   (log/error :mkdir-recur! {:path dir
-                                             :error error})))))
-  (readdir [_this dir]                  ; recursive
-    (let [dir (path/path-normalize dir)]
-      (get-file-paths dir)))
-  (unlink! [this repo fpath _opts]
-    (p/let [repo-dir (config/get-local-dir repo)
-            recycle-dir (path/path-join repo-dir config/app-name ".recycle") ;; logseq/.recycle
-            ;; convert url to pure path
-            file-name (-> (path/trim-dir-prefix repo-dir fpath)
-                          (string/replace "/" "_"))
-            new-path (path/path-join recycle-dir file-name)
-            _ (protocol/mkdir-recur! this recycle-dir)]
-      (protocol/rename! this repo fpath new-path)))
-  (rmdir! [_this _dir]
-    ;; Too dangerous!!! We'll never implement this.
-    nil)
-  (read-file [_this dir path _options]
-    (let [fpath (path/path-join dir path)]
-      (->
-       (<read-file-with-utf8 fpath)
-       (p/catch (fn [error]
-                  (log/error :read-file-failed error))))))
-  (write-file! [_this repo dir path content opts]
-    (let [fpath (path/path-join dir path)]
-      (p/let [stat (p/catch
-                    (.stat Filesystem (clj->js {:path fpath}))
-                    (fn [_e] :not-found))]
-        ;; `path` is full-path
-        (write-file-impl! repo dir path content opts stat))))
-  (rename! [_this _repo old-fpath new-fpath]
-    (-> (.rename Filesystem
-                 (clj->js
-                  {:from old-fpath
-                   :to new-fpath}))
-        (p/catch (fn [error]
-                   (log/error :rename-file-failed error)))))
-  (copy! [_this _repo old-path new-path]
-    (-> (.copy Filesystem
-               (clj->js
-                {:from old-path
-                 :to new-path}))
-        (p/catch (fn [error]
-                   (log/error :copy-file-failed error)))))
-  (stat [_this fpath]
-    (-> (p/chain (.stat Filesystem (clj->js {:path fpath}))
-                 #(js->clj % :keywordize-keys true))
-        (p/catch (fn [error]
-                   (let [errstr (if error (.toString error) "")]
-                     (when (string/includes? errstr "because you don’t have permission to view it")
-                       (state/pub-event! [:notification/show
-                                          {:content "No permission, please clear cache and re-open graph folder."
-                                           :status :error}]))
-                     (p/rejected error))))))
-  (open-dir [_this dir]
-    (open-dir dir))
-  (get-files [_this dir]
-    (get-files dir))
-  (watch-dir! [_this dir _options]
-    (p/let [_ (.unwatch mobile-util/fs-watcher)]
-      (.watch mobile-util/fs-watcher (clj->js {:path dir}))))
-  (unwatch-dir! [_this _dir]
-    (.unwatch mobile-util/fs-watcher)))

+ 0 - 366
src/main/frontend/fs/nfs.cljs

@@ -1,366 +0,0 @@
-(ns frontend.fs.nfs
-  "Browser File System API based fs implementation.
-
-   Rationale:
-   - nfs-file-handles-cache stores all file & directory handle
-   - idb stores top-level directory handle
-   - readdir/get-files is called by re-index and initial watcher to init all handles"
-  (:require [frontend.fs.protocol :as protocol]
-            [frontend.util :as util]
-            [clojure.string :as string]
-            [frontend.idb :as idb]
-            [promesa.core :as p]
-            [lambdaisland.glogi :as log]
-            [goog.object :as gobj]
-            [frontend.db :as db]
-            [frontend.config :as config]
-            [frontend.state :as state]
-            [frontend.handler.notification :as notification]
-            ["/frontend/utils" :as utils]
-            [logseq.common.util :as common-util]
-            [logseq.common.path :as path]))
-
-;; Cache the file handles in the memory so that
-;; the browser will not keep asking permissions.
-(defonce nfs-file-handles-cache (atom {}))
-
-(defn- get-nfs-file-handle
-  [handle-path]
-  (get @nfs-file-handles-cache handle-path))
-
-(defn add-nfs-file-handle!
-  [handle-path handle]
-  (prn ::DEBUG "add-nfs-file-handle!" handle-path)
-  (swap! nfs-file-handles-cache assoc handle-path handle))
-
-(defn remove-nfs-file-handle!
-  [handle-path]
-  (swap! nfs-file-handles-cache dissoc handle-path))
-
-(defn- nfs-saved-handler
-  [repo path file]
-  (when-let [last-modified (gobj/get file "lastModified")]
-    ;; TODO: extract
-    (let [path (if (= \/ (first path))
-                 (subs path 1)
-                 path)]
-      ;; Bad code
-      (db/set-file-last-modified-at! repo path last-modified))))
-
-(defn- verify-handle-permission
-  [handle read-write?]
-  (utils/verifyPermission handle read-write?))
-
-(defn verify-permission
-  [repo read-write?]
-  (let [repo (or repo (state/get-current-repo))
-        repo-dir (config/get-repo-dir repo)
-        handle-path (str "handle/" repo-dir)
-        handle (get-nfs-file-handle handle-path)]
-    (p/then
-     (utils/verifyPermission handle read-write?)
-     (fn []
-       (state/set-state! [:nfs/user-granted? repo] true)
-       true))))
-
-(defn check-directory-permission!
-  [repo]
-  (when (config/local-file-based-graph? repo)
-    (p/let [repo-dir (config/get-repo-dir repo)
-            handle-path (str "handle/" repo-dir)
-            handle (idb/get-item handle-path)]
-      (when handle
-        (add-nfs-file-handle! handle-path handle)
-        (verify-permission repo true)))))
-
-(defn- contents-matched?
-  [disk-content db-content]
-  (when (and (string? disk-content) (string? db-content))
-    (= (string/trim disk-content) (string/trim db-content))))
-
-(defn- await-permission-granted
-  "Guard against File System Access API permission, avoiding early access before granted"
-  [repo]
-  (if (state/nfs-user-granted? repo)
-    (p/resolved true)
-    (js/Promise. (fn [resolve reject]
-                   (let [timer (atom nil)
-                         timer' (js/setInterval (fn []
-                                                  (when (state/nfs-user-granted? repo)
-                                                    (js/clearInterval @timer)
-                                                    (resolve true)))
-                                                1000)
-                         _ (reset! timer timer')]
-                     (js/setTimeout (fn []
-                                      (js/clearInterval timer)
-                                      (reject false))
-                                    100000))))))
-
-(defn await-get-nfs-file-handle
-  "for accessing File handle outside, ensuring user granted."
-  [repo handle-path]
-  (p/let [_ (await-permission-granted repo)]
-    (get-nfs-file-handle handle-path)))
-
-(defn- readdir-and-reload-all-handles
-  "Return list of filenames"
-  [root-dir root-handle]
-  (p/let [files (utils/getFiles root-handle
-                                true
-                                (fn [path entry]
-                                  (let [handle-path (str "handle/" path)]
-                                    ;; Same for all handles here, even for directories and ignored directories(for backing up)
-                                    ;; FileSystemDirectoryHandle or FileSystemFileHandle
-                                    (when-not (string/includes? path "/.")
-                                      (add-nfs-file-handle! handle-path entry)))))]
-    (->> files
-         (remove  (fn [file]
-                    (let [rpath (string/replace-first (.-webkitRelativePath file) (str root-dir "/") "")
-                          ext (util/get-file-ext rpath)]
-                      (or  (string/blank? rpath)
-                           (string/starts-with? rpath ".")
-                           (string/starts-with? rpath "logseq/bak")
-                           ; (string/starts-with? rpath "logseq/version-files")
-                           (not (contains? #{"md" "org" "excalidraw" "edn" "css"} ext))))))
-         (map (fn [file]
-                (-> (.-webkitRelativePath file)
-                    common-util/path-normalize))))))
-
-
-(defn- get-files-and-reload-all-handles
-  "Return list of file objects"
-  [root-dir root-handle]
-  (p/let [files (utils/getFiles root-handle
-                                true
-                                (fn [path entry]
-                                  (let [handle-path (str "handle/" path)]
-                                    ;; Same for all handles here, even for directories and ignored directories(for backing up)
-                                    ;; FileSystemDirectoryHandle or FileSystemFileHandle
-                                    (when-not (string/includes? path "/.")
-                                      (add-nfs-file-handle! handle-path entry)))))]
-    (p/all (->> files
-                (remove  (fn [file]
-                           (let [rpath (string/replace-first (.-webkitRelativePath file) (str root-dir "/") "")
-                                 ext (util/get-file-ext rpath)]
-                             (or  (string/blank? rpath)
-                                  (string/starts-with? rpath ".")
-                                  (string/starts-with? rpath "logseq/bak")
-                                  (string/starts-with? rpath "logseq/version-files")
-                                  (not (contains? #{"md" "org" "excalidraw" "edn" "css"} ext))))))
-                ;; Read out using .text, Promise<string>
-                (map (fn [file]
-                       (p/let [content (.text file)]
-                         {:name        (.-name file)
-                          :path        (-> (.-webkitRelativePath file)
-                                           common-util/path-normalize)
-                          :mtime       (.-lastModified file)
-                          :size        (.-size file)
-                          :type        (.-kind (.-handle file))
-                          :content     content
-                          :file/file   file})))))))
-
-(defrecord ^:large-vars/cleanup-todo Nfs []
-  protocol/Fs
-  (mkdir! [_this dir]
-    (let [dir (path/path-normalize dir)
-          parent-dir (path/parent dir)
-
-          parent-handle-path (str "handle/" parent-dir)]
-      (-> (p/let [parent-handle (or (get-nfs-file-handle parent-handle-path)
-                                    (idb/get-item parent-handle-path))
-                  _ (when parent-handle (verify-handle-permission parent-handle true))]
-            (when parent-handle
-              (p/let [new-dir-name (path/filename dir)
-                      new-handle (.getDirectoryHandle ^js parent-handle new-dir-name
-                                                      #js {:create true})
-                      handle-path (str "handle/" dir)
-                      _ (idb/set-item! handle-path new-handle)]
-                (add-nfs-file-handle! handle-path new-handle)
-                (println "dir created: " dir))))
-          (p/catch (fn [error]
-                     (js/console.debug "mkdir error: " error ", dir: " dir)
-                     (throw error))))))
-
-  (mkdir-recur! [this dir]
-    (protocol/mkdir! this dir))
-
-  (readdir [_this dir]
-    ;; This method is only used for repo-dir and version-files dir
-    ;; There's no Logseq Sync support for nfs. So assume dir is always a repo dir.
-    (p/let [repo-url (str "logseq_local_" dir)
-            _ (await-permission-granted repo-url)
-            handle-path (str "handle/" dir)
-            handle (or (get-nfs-file-handle handle-path)
-                       (idb/get-item handle-path))
-            _ (when handle
-                (verify-handle-permission handle true))
-            fpaths (if (string/includes? dir "/")
-                     (js/console.error "ERROR: unimpl")
-                     (readdir-and-reload-all-handles dir handle))]
-      fpaths))
-
-  (unlink! [this repo fpath _opts]
-    (let [repo-dir (config/get-repo-dir repo)
-          filename (path/filename fpath)
-          handle-path (str "handle/" fpath)
-          recycle-dir (path/path-join repo-dir config/app-name config/recycle-dir)]
-      (->
-       (p/let [_ (protocol/mkdir! this recycle-dir)
-               handle (get-nfs-file-handle handle-path)
-               file (.getFile handle)
-               content (.text file)
-
-               bak-handle (get-nfs-file-handle (str "handle/" recycle-dir))
-               bak-filename (-> (path/relative-path repo-dir fpath)
-                                (string/replace "/" "_")
-                                (string/replace "\\" "_"))
-               file-handle (.getFileHandle ^js bak-handle bak-filename #js {:create true})
-               _ (utils/writeFile file-handle content)
-
-               parent-dir (path/parent fpath)
-               parent-handle (get-nfs-file-handle (str "handle/" parent-dir))
-               _ (when parent-handle
-                   (.removeEntry ^js parent-handle filename))]
-         (idb/remove-item! handle-path)
-         (remove-nfs-file-handle! handle-path))
-       (p/catch (fn [error]
-                  (log/error :unlink/path {:path fpath
-                                           :error error}))))))
-
-  (rmdir! [_this _dir]
-    nil)
-
-  (read-file [_this dir path _options]
-    (p/let [fpath (path/path-join dir path)
-            handle-path (str "handle/" fpath)]
-      (p/let [handle (or (get-nfs-file-handle handle-path)
-                         (idb/get-item handle-path))
-              local-file (and handle (.getFile handle))]
-        (and local-file (.text local-file)))))
-
-  (write-file! [_this repo dir path content opts]
-    ;; TODO: file backup handling
-    (let [fpath (path/path-join dir path)
-          ext (util/get-file-ext path)
-          file-handle-path (str "handle/" fpath)]
-      (p/let [file-handle (get-nfs-file-handle file-handle-path)]
-        (if file-handle
-          ;; file exist
-          (p/let [local-file (.getFile file-handle)
-                  disk-content (.text local-file)
-                  db-content (db/get-file repo path)
-                  contents-matched?' (contents-matched? disk-content db-content)]
-            (if (and
-                 (not (string/blank? db-content))
-                 (not (:skip-compare? opts))
-                 (not contents-matched?')
-                 (not (contains? #{"excalidraw" "edn" "css"} ext))
-                 (not (string/includes? path "/.recycle/")))
-              (state/pub-event! [:file/not-matched-from-disk path disk-content content])
-              (p/let [_ (verify-permission repo true)
-                      _ (utils/writeFile file-handle content)
-                      file (.getFile file-handle)]
-                (when file
-                  (db/set-file-content! repo path content)
-                  (nfs-saved-handler repo path file)))))
-          ;; file no-exist, write via parent dir handle
-          (p/let [basename (path/filename fpath)
-                  parent-dir (path/parent fpath)
-                  parent-dir-handle-path (str "handle/" parent-dir)
-                  parent-dir-handle (get-nfs-file-handle parent-dir-handle-path)]
-
-            (if parent-dir-handle
-              ;; create from directory handle
-              (p/let [file-handle (.getFileHandle ^js parent-dir-handle basename #js {:create true})
-                      _  (add-nfs-file-handle! file-handle-path file-handle)
-                      file (.getFile file-handle)
-                      text (.text file)]
-                (if (string/blank? text)
-                  (p/let [;; _ (idb/set-item! file-handle-path file-handle)
-                          _ (utils/writeFile file-handle content)
-                          file (.getFile file-handle)]
-                    (when file
-                      (nfs-saved-handler repo path file)))
-                  (do
-                    (notification/show! (str "The file " path " already exists, please append the content if you need it.\n Unsaved content: \n" content)
-                                        :warning
-                                        false)
-                    (state/pub-event! [:file/alter repo path text]))))
-
-              ;; TODO(andelf): Create parent directory and write
-              ;; Normally directory are created layer by layer. So it's safe to leave this unimplemented.
-              (js/console.error "TODO: can not create directory hierarchy")))))))
-
-  (rename! [this repo old-path new-path]
-    (p/let [repo-dir (config/get-repo-dir repo)
-            old-rpath (path/relative-path repo-dir old-path)
-            new-rpath (path/relative-path repo-dir new-path)
-            old-content (protocol/read-file this repo-dir old-rpath nil)
-            _ (protocol/write-file! this repo repo-dir new-rpath old-content nil)
-            _ (protocol/unlink! this repo old-path nil)]))
-
-  (stat [_this fpath]
-    (if-let [handle (get-nfs-file-handle (str "handle/" fpath))]
-      (p/let [_ (verify-handle-permission handle true)
-              file (.getFile handle)]
-        (let [get-attr #(gobj/get file %)]
-          {:last-modified-at (get-attr "lastModified")
-           :size (get-attr "size")
-           :path fpath
-           :type (get-attr "type")}))
-      (p/rejected "File not exists")))
-
-  (open-dir [_this _dir]
-    (p/let [files (utils/openDirectory #js {:recursive true
-                                            :mode "readwrite"}
-                                       (fn [path entry]
-                                         (let [handle-path (str "handle/" path)]
-                                           ;; Same all handles here, even for directories and ignored directories(for backing up)
-                                           ;; FileSystemDirectoryHandle or FileSystemFileHandle
-                                           (when-not (string/includes? path "/.")
-                                             (add-nfs-file-handle! handle-path entry)))))
-            dir-handle (first files) ;; FileSystemDirectoryHandle
-            dir-name (.-name dir-handle)
-            files (->> (next files)
-                       (remove  (fn [file]
-                                  (let [rpath (.-webkitRelativePath file) ;
-                                        ; (string/replace-first (.-webkitRelativePath file) (str dir-name "/") "")
-                                        ext (util/get-file-ext rpath)]
-                                    (or  (string/blank? rpath)
-                                         (string/starts-with? rpath ".")
-                                         (string/starts-with? rpath "logseq/bak")
-                                         (string/starts-with? rpath "logseq/version-files")
-                                         (not (contains? #{"md" "org" "excalidraw" "edn" "css"} ext))))))
-                       ;; Read out using .text, Promise<string>
-                       (map (fn [file]
-                              (js/console.log "handle" file)
-                              (p/let [content (.text file)]
-                                ;; path content size mtime
-                                {:name        (.-name file)
-                                 :path        (-> (.-webkitRelativePath file)
-                                                  common-util/path-normalize)
-                                 :mtime       (.-lastModified file)
-                                 :size        (.-size file)
-                                 :type        (.-kind (.-handle file))
-                                 :content     content
-                                 ;; expose the following, they are used by the file system
-                                 :file/file   file}))))
-            files (p/all files)]
-      (add-nfs-file-handle! (str "handle/" dir-name) dir-handle)
-      (idb/set-item! (str "handle/" dir-name) dir-handle)
-      {:path dir-name
-       :files files}))
-
-  (get-files [_this dir]
-    (when (string/includes? dir "/")
-      (js/console.error "BUG: get-files(nfs) only accepts repo-dir"))
-    (p/let [handle-path (str "handle/" dir)
-            handle (get-nfs-file-handle handle-path)
-            files (get-files-and-reload-all-handles dir handle)]
-      files))
-
-  (watch-dir! [_this _dir _options]
-    nil)
-
-  (unwatch-dir! [_this _dir]
-    nil))

+ 74 - 300
src/main/frontend/fs/sync.cljs

@@ -1,7 +1,6 @@
 (ns frontend.fs.sync
 (ns frontend.fs.sync
   "Main ns for providing file sync functionality"
   "Main ns for providing file sync functionality"
-  (:require ["@capawesome/capacitor-background-task" :refer [BackgroundTask]]
-            ["path" :as node-path]
+  (:require ["path" :as node-path]
             [cljs-http.client :as http]
             [cljs-http.client :as http]
             [cljs-time.coerce :as tc]
             [cljs-time.coerce :as tc]
             [cljs-time.core :as t]
             [cljs-time.core :as t]
@@ -23,12 +22,10 @@
             [frontend.diff :as diff]
             [frontend.diff :as diff]
             [frontend.encrypt :as encrypt]
             [frontend.encrypt :as encrypt]
             [frontend.fs :as fs]
             [frontend.fs :as fs]
-            [frontend.fs.capacitor-fs :as capacitor-fs]
             [frontend.fs.diff-merge :as diff-merge]
             [frontend.fs.diff-merge :as diff-merge]
             [frontend.handler.file-based.file :as file-handler]
             [frontend.handler.file-based.file :as file-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
             [frontend.handler.user :as user]
             [frontend.handler.user :as user]
-            [frontend.mobile.util :as mobile-util]
             [frontend.pubsub :as pubsub]
             [frontend.pubsub :as pubsub]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.util :as util]
             [frontend.util :as util]
@@ -164,8 +161,7 @@
                  :remote->local-full-sync-failed
                  :remote->local-full-sync-failed
                  :local->remote-full-sync-failed
                  :local->remote-full-sync-failed
                  :get-remote-graph-failed
                  :get-remote-graph-failed
-                 :get-deletion-logs-failed
-                 })
+                 :get-deletion-logs-failed})
 
 
 (s/def ::sync-event (s/keys :req-un [::event ::data]))
 (s/def ::sync-event (s/keys :req-un [::event ::data]))
 
 
@@ -198,7 +194,6 @@
   [x]
   [x]
   (when (instance? ExceptionInfo x) x))
   (when (instance? ExceptionInfo x) x))
 
 
-
 (def ws-addr config/WS-URL)
 (def ws-addr config/WS-URL)
 
 
 ;; Warning: make sure to `persist-var/-load` graphs-txid before using it.
 ;; Warning: make sure to `persist-var/-load` graphs-txid before using it.
@@ -326,9 +321,9 @@
 (defn <request [api-name & args]
 (defn <request [api-name & args]
   (let [name (str api-name (.now js/Date))]
   (let [name (str api-name (.now js/Date))]
     (go (swap! *on-flying-request conj name)
     (go (swap! *on-flying-request conj name)
-      (let [r (<! (apply <request* api-name args))]
-        (swap! *on-flying-request disj name)
-        r))))
+        (let [r (<! (apply <request* api-name args))]
+          (swap! *on-flying-request disj name)
+          r))))
 
 
 (defn- remove-dir-prefix [dir path]
 (defn- remove-dir-prefix [dir path]
   (let [r (string/replace path (js/RegExp. (str "^" (gstring/regExpEscape dir))) "")]
   (let [r (string/replace path (js/RegExp. (str "^" (gstring/regExpEscape dir))) "")]
@@ -417,19 +412,19 @@
   (let [update? (= "update_files" TXType)
   (let [update? (= "update_files" TXType)
         delete? (= "delete_files" TXType)
         delete? (= "delete_files" TXType)
         update-xf
         update-xf
-                (comp
-                 (remove #(or (empty? (first %))
-                              (empty? (last %))))
-                 (map #(->FileTxn (first %) (first %) update? delete? TXId (last %))))
+        (comp
+         (remove #(or (empty? (first %))
+                      (empty? (last %))))
+         (map #(->FileTxn (first %) (first %) update? delete? TXId (last %))))
         delete-xf
         delete-xf
-                (comp
-                 (remove #(empty? (first %)))
-                 (map #(->FileTxn (first %) (first %) update? delete? TXId nil)))
+        (comp
+         (remove #(empty? (first %)))
+         (map #(->FileTxn (first %) (first %) update? delete? TXId nil)))
         rename-xf
         rename-xf
-                (comp
-                 (remove #(or (empty? (first %))
-                              (empty? (second %))))
-                 (map #(->FileTxn (second %) (first %) false false TXId nil)))
+        (comp
+         (remove #(or (empty? (first %))
+                      (empty? (second %))))
+         (map #(->FileTxn (second %) (first %) false false TXId nil)))
         xf (case TXType
         xf (case TXType
              "delete_files" delete-xf
              "delete_files" delete-xf
              "update_files" update-xf
              "update_files" update-xf
@@ -560,7 +555,6 @@
    (map-indexed filepath+checksum->diff)
    (map-indexed filepath+checksum->diff)
    (diffs->partitioned-filetxns n)))
    (diffs->partitioned-filetxns n)))
 
 
-
 (deftype FileMetadata [size etag path encrypted-path last-modified remote? txid ^:mutable normalized-path]
 (deftype FileMetadata [size etag path encrypted-path last-modified remote? txid ^:mutable normalized-path]
   Object
   Object
   (get-normalized-path [_]
   (get-normalized-path [_]
@@ -596,13 +590,10 @@
       :txid txid
       :txid txid
       not-found))
       not-found))
 
 
-
   IPrintWithWriter
   IPrintWithWriter
   (-pr-writer [_ w _opts]
   (-pr-writer [_ w _opts]
     (write-all w (str {:size size :etag etag :path path :remote? remote? :txid txid :last-modified last-modified}))))
     (write-all w (str {:size size :etag etag :path path :remote? remote? :txid txid :last-modified last-modified}))))
 
 
-
-
 (def ^:private higher-priority-remote-files
 (def ^:private higher-priority-remote-files
   "when diff all remote files and local files, following remote files always need to download(when checksum not matched),
   "when diff all remote files and local files, following remote files always need to download(when checksum not matched),
   even local-file's last-modified > remote-file's last-modified.
   even local-file's last-modified > remote-file's last-modified.
@@ -659,21 +650,21 @@
    #{} s1))
    #{} s1))
 
 
 (comment
 (comment
- (defn map->FileMetadata [m]
-   (apply ->FileMetadata ((juxt :size :etag :path :encrypted-path :last-modified :remote? (constantly nil)) m)))
-
- (assert
-  (=
-   #{(map->FileMetadata {:size 1 :etag 2 :path 2 :encrypted-path 2 :last-modified 2})}
-   (diff-file-metadata-sets
-    (into #{}
-          (map map->FileMetadata)
-          [{:size 1 :etag 1 :path 1 :encrypted-path 1 :last-modified 1}
-           {:size 1 :etag 2 :path 2 :encrypted-path 2 :last-modified 2}])
-    (into #{}
-          (map map->FileMetadata)
-          [{:size 1 :etag 1 :path 1 :encrypted-path 1 :last-modified 1}
-           {:size 1 :etag 1 :path 2 :encrypted-path 2 :last-modified 1}])))))
+  (defn map->FileMetadata [m]
+    (apply ->FileMetadata ((juxt :size :etag :path :encrypted-path :last-modified :remote? (constantly nil)) m)))
+
+  (assert
+   (=
+    #{(map->FileMetadata {:size 1 :etag 2 :path 2 :encrypted-path 2 :last-modified 2})}
+    (diff-file-metadata-sets
+     (into #{}
+           (map map->FileMetadata)
+           [{:size 1 :etag 1 :path 1 :encrypted-path 1 :last-modified 1}
+            {:size 1 :etag 2 :path 2 :encrypted-path 2 :last-modified 2}])
+     (into #{}
+           (map map->FileMetadata)
+           [{:size 1 :etag 1 :path 1 :encrypted-path 1 :last-modified 1}
+            {:size 1 :etag 1 :path 2 :encrypted-path 2 :last-modified 1}])))))
 
 
 (extend-protocol IChecksum
 (extend-protocol IChecksum
   FileMetadata
   FileMetadata
@@ -726,7 +717,6 @@
 
 
   common-util/path-normalize)
   common-util/path-normalize)
 
 
-
 ;;; ### APIs
 ;;; ### APIs
 ;; `RSAPI` call apis through rsapi package, supports operations on files
 ;; `RSAPI` call apis through rsapi package, supports operations on files
 
 
@@ -765,16 +755,13 @@
   (<get-graph-encrypt-keys [this graph-uuid])
   (<get-graph-encrypt-keys [this graph-uuid])
   (<upload-graph-encrypt-keys [this graph-uuid public-key encrypted-private-key]))
   (<upload-graph-encrypt-keys [this graph-uuid public-key encrypted-private-key]))
 
 
-
 (defprotocol IRemoteControlAPI
 (defprotocol IRemoteControlAPI
   "api functions provided for outside the sync process"
   "api functions provided for outside the sync process"
-  (<delete-remote-files-control [this graph-uuid filepaths])
-  )
+  (<delete-remote-files-control [this graph-uuid filepaths]))
 
 
 (defprotocol IToken
 (defprotocol IToken
   (<get-token [this]))
   (<get-token [this]))
 
 
-
 (defn <case-different-local-file-exist?
 (defn <case-different-local-file-exist?
   "e.g. filepath=\"pages/Foo.md\"
   "e.g. filepath=\"pages/Foo.md\"
   found-filepath=\"pages/foo.md\"
   found-filepath=\"pages/foo.md\"
@@ -921,149 +908,10 @@
   (<add-new-version [_this repo path content]
   (<add-new-version [_this repo path content]
     (p->c (ipc/ipc "addVersionFile" (config/get-local-dir repo) path content))))
     (p->c (ipc/ipc "addVersionFile" (config/get-local-dir repo) path content))))
 
 
-(deftype ^:large-vars/cleanup-todo CapacitorAPI [^:mutable graph-uuid' ^:mutable private-key ^:mutable public-key']
-  IToken
-  (<get-token [_this]
-    (user/<wrap-ensure-id&access-token
-     (state/get-auth-id-token)))
-
-  IRSAPI
-  (rsapi-ready? [_ graph-uuid] (and (= graph-uuid graph-uuid') private-key public-key'))
-  (<key-gen [_]
-    (go (let [r (<! (p->c (.keygen mobile-util/file-sync #js {})))]
-          (-> r
-              (js->clj :keywordize-keys true)))))
-  (<set-env [_ graph-uuid prod? secret-key public-key]
-    (set! graph-uuid' graph-uuid)
-    (set! private-key secret-key)
-    (set! public-key' public-key)
-    (p->c (.setEnv mobile-util/file-sync (clj->js {:graphUUID graph-uuid
-                                                   :env (if prod? "prod" "dev")
-                                                   :secretKey secret-key
-                                                   :publicKey public-key}))))
-
-  (<get-local-all-files-meta [this graph-uuid base-path]
-    (go
-      (let [r (<! (p->c (.getLocalAllFilesMeta mobile-util/file-sync (clj->js {:graphUUID graph-uuid
-                                                                               :basePath base-path}))))]
-        (or (guard-ex r)
-            (<! (<build-local-file-metadatas this graph-uuid (.-result r)))))))
-
-  (<get-local-files-meta [this graph-uuid base-path filepaths]
-    (go
-      (let [r (<! (p->c (.getLocalFilesMeta mobile-util/file-sync
-                                            (clj->js {:graphUUID graph-uuid
-                                                      :basePath base-path
-                                                      :filePaths filepaths}))))]
-        (assert (not (instance? ExceptionInfo r)) "get-local-files-meta shouldn't return exception")
-        (<! (<build-local-file-metadatas this graph-uuid (.-result r))))))
-
-  (<rename-local-file [_ graph-uuid base-path from to]
-    (p->c (.renameLocalFile mobile-util/file-sync
-                            (clj->js {:graphUUID graph-uuid
-                                      :basePath base-path
-                                      :from (path-normalize from)
-                                      :to (path-normalize to)}))))
-
-  (<update-local-files [this graph-uuid base-path filepaths]
-    (go
-      (let [token-or-exp (<! (<get-token this))
-            filepaths' (map path-normalize filepaths)]
-        (or (guard-ex token-or-exp)
-            (<! (p->c (.updateLocalFiles mobile-util/file-sync (clj->js {:graphUUID graph-uuid
-                                                                         :basePath base-path
-                                                                         :filePaths filepaths'
-                                                                         :token token-or-exp}))))))))
-  (<fetch-remote-files [this graph-uuid base-path filepaths]
-    (go
-      (let [token-or-exp (<! (<get-token this))]
-        (or (guard-ex token-or-exp)
-            (js->clj
-             (.-value
-              (<! (<retry-rsapi
-                   #(p->c (.fetchRemoteFiles mobile-util/file-sync
-                                             (clj->js {:graphUUID graph-uuid
-                                                       :basePath base-path
-                                                       :filePaths filepaths
-                                                       :token token-or-exp})))))))))))
-  (<download-version-files [this graph-uuid base-path filepaths]
-    (go
-      (let [token-or-exp (<! (<get-token this))]
-        (or (guard-ex token-or-exp)
-            (<! (<retry-rsapi
-                 #(p->c (.updateLocalVersionFiles mobile-util/file-sync
-                                                  (clj->js {:graphUUID graph-uuid
-                                                            :basePath base-path
-                                                            :filePaths filepaths
-                                                            :token token-or-exp})))))))))
-
-  (<delete-local-files [_ graph-uuid base-path filepaths]
-    (let [normalized-filepaths (mapv path-normalize filepaths)]
-      (go
-        (let [r (<! (<retry-rsapi #(p->c (.deleteLocalFiles mobile-util/file-sync
-                                                            (clj->js {:graphUUID graph-uuid
-                                                                      :basePath base-path
-                                                                      :filePaths normalized-filepaths})))))]
-          r))))
-
-  (<update-remote-files [this graph-uuid base-path filepaths local-txid]
-    (let [normalized-filepaths (mapv path-normalize filepaths)]
-      (go
-        (let [token-or-exp (<! (<get-token this))
-              r (or (guard-ex token-or-exp)
-                    (<! (p->c (.updateRemoteFiles mobile-util/file-sync
-                                                  (clj->js {:graphUUID graph-uuid
-                                                            :basePath base-path
-                                                            :filePaths normalized-filepaths
-                                                            :txid local-txid
-                                                            :token token-or-exp
-                                                            :fnameEncryption true})))))]
-          (or (guard-ex r)
-              (get (js->clj r) "txid"))))))
-
-  (<delete-remote-files [this graph-uuid base-path filepaths local-txid]
-    (let [normalized-filepaths (mapv path-normalize filepaths)]
-      (go
-        (let [token-or-exp (<! (<get-token this))
-              r (or (guard-ex token-or-exp)
-                    (<! (p->c (.deleteRemoteFiles mobile-util/file-sync
-                                                  (clj->js {:graphUUID graph-uuid
-                                                            :basePath base-path
-                                                            :filePaths normalized-filepaths
-                                                            :txid local-txid
-                                                            :token token-or-exp})))))]
-          (or (guard-ex r)
-              (get (js->clj r) "txid"))))))
-
-  (<encrypt-fnames [_ graph-uuid fnames]
-    (go
-      (let [r (<! (p->c (.encryptFnames mobile-util/file-sync
-                                        (clj->js {:graphUUID graph-uuid
-                                                  :filePaths fnames}))))]
-        (or (guard-ex r)
-            (get (js->clj r) "value")))))
-  (<decrypt-fnames [_ graph-uuid fnames]
-    (go (let [r (<! (p->c (.decryptFnames mobile-util/file-sync
-                                          (clj->js {:graphUUID graph-uuid
-                                                    :filePaths fnames}))))]
-          (if (instance? ExceptionInfo r)
-            (ex-info "decrypt-failed" {:fnames fnames} (ex-cause r))
-            (get (js->clj r) "value")))))
-  (<cancel-all-requests [_]
-    (p->c (.cancelAllRequests mobile-util/file-sync)))
-  (<add-new-version [_this repo path content]
-    (p->c (capacitor-fs/backup-file repo :version-file-dir path content))))
-
 (def rsapi (cond
 (def rsapi (cond
              (util/electron?)
              (util/electron?)
              (->RSAPI nil nil nil)
              (->RSAPI nil nil nil)
 
 
-             (mobile-util/native-ios?)
-             (->CapacitorAPI nil nil nil)
-
-             (mobile-util/native-android?)
-             (->CapacitorAPI nil nil nil)
-
              :else
              :else
              nil))
              nil))
 
 
@@ -1128,8 +976,8 @@
      (go-loop []
      (go-loop []
        (let [{:keys [val stop]}
        (let [{:keys [val stop]}
              (async/alt!
              (async/alt!
-              debug-print-sync-events-loop-stop-chan {:stop true}
-              out-ch ([v] {:val v}))]
+               debug-print-sync-events-loop-stop-chan {:stop true}
+               out-ch ([v] {:val v}))]
          (cond
          (cond
            stop (do (async/unmix-all out-mix)
            stop (do (async/unmix-all out-mix)
                     (doseq [[topic ch] topic&chs]
                     (doseq [[topic ch] topic&chs]
@@ -1138,12 +986,10 @@
            val (do (pp/pprint [:debug :sync-event val])
            val (do (pp/pprint [:debug :sync-event val])
                    (recur))))))))
                    (recur))))))))
 
 
-
 (defn stop-debug-print-sync-events-loop
 (defn stop-debug-print-sync-events-loop
   []
   []
   (offer! debug-print-sync-events-loop-stop-chan true))
   (offer! debug-print-sync-events-loop-stop-chan true))
 
 
-
 ;;; sync events ends
 ;;; sync events ends
 
 
 (defn- fire-file-sync-storage-exceed-limit-event!
 (defn- fire-file-sync-storage-exceed-limit-event!
@@ -1232,7 +1078,6 @@
                 (recur result-file-meta-list others))))
                 (recur result-file-meta-list others))))
         (vals (persistent! result-file-meta-list))))))
         (vals (persistent! result-file-meta-list))))))
 
 
-
 (extend-type RemoteAPI
 (extend-type RemoteAPI
   IRemoteAPI
   IRemoteAPI
   (<user-info [this]
   (<user-info [this]
@@ -1438,13 +1283,10 @@
 
 
 (comment
 (comment
   (declare remoteapi)
   (declare remoteapi)
-  (<delete-remote-files-control remoteapi (second @graphs-txid) ["pages/aa.md"])
-
-  )
+  (<delete-remote-files-control remoteapi (second @graphs-txid) ["pages/aa.md"]))
 
 
 (def remoteapi (->RemoteAPI nil))
 (def remoteapi (->RemoteAPI nil))
 
 
-
 (def ^:private *get-graph-salt-memoize-cache (atom {}))
 (def ^:private *get-graph-salt-memoize-cache (atom {}))
 (defn update-graph-salt-cache [graph-uuid v]
 (defn update-graph-salt-cache [graph-uuid v]
   {:pre [(map? v)
   {:pre [(map? v)
@@ -1521,9 +1363,6 @@
           val val
           val val
           timeout' (recur))))))
           timeout' (recur))))))
 
 
-
-
-
 (defn- assert-local-txid<=remote-txid
 (defn- assert-local-txid<=remote-txid
   []
   []
   (when-let [local-txid (last @graphs-txid)]
   (when-let [local-txid (last @graphs-txid)]
@@ -1548,7 +1387,6 @@
          sync-state--remove-recent-remote->local-files
          sync-state--remove-recent-remote->local-files
          sync-state--stopped?)
          sync-state--stopped?)
 
 
-
 (defn- filetxns=>recent-remote->local-files
 (defn- filetxns=>recent-remote->local-files
   [filetxns]
   [filetxns]
   (let [{:keys [update-filetxns delete-filetxns rename-filetxns]}
   (let [{:keys [update-filetxns delete-filetxns rename-filetxns]}
@@ -1610,7 +1448,7 @@
                                       (fs/unlink! repo (path/path-join repo-dir base-file) {}))
                                       (fs/unlink! repo (path/path-join repo-dir base-file) {}))
                                      ;; base-content != current-content, merge, do not delete
                                      ;; base-content != current-content, merge, do not delete
                                      (p/let [merged-content (diff-merge/three-way-merge base-content "" current-content format)]
                                      (p/let [merged-content (diff-merge/three-way-merge base-content "" current-content format)]
-                                       (fs/write-file! repo repo-dir current-change-file merged-content {:skip-compare? true})
+                                       (fs/write-plain-text-file! repo repo-dir current-change-file merged-content {:skip-compare? true})
                                        (file-handler/alter-file repo current-change-file merged-content {:re-render-root? true
                                        (file-handler/alter-file repo current-change-file merged-content {:re-render-root? true
                                                                                                          :from-disk? true
                                                                                                          :from-disk? true
                                                                                                          :fs/event :fs/remote-file-change}))))
                                                                                                          :fs/event :fs/remote-file-change}))))
@@ -1660,7 +1498,7 @@
                                                     merged-content (diff-merge/three-way-merge base-content incoming-content current-content format)]
                                                     merged-content (diff-merge/three-way-merge base-content incoming-content current-content format)]
                                               (when (seq merged-content)
                                               (when (seq merged-content)
                                                 (p/do!
                                                 (p/do!
-                                                 (fs/write-file! repo repo-dir current-change-file merged-content {:skip-compare? true})
+                                                 (fs/write-plain-text-file! repo repo-dir current-change-file merged-content {:skip-compare? true})
                                                  (file-handler/alter-file repo current-change-file merged-content {:re-render-root? true
                                                  (file-handler/alter-file repo current-change-file merged-content {:re-render-root? true
                                                                                                                    :from-disk? true
                                                                                                                    :from-disk? true
                                                                                                                    :fs/event :fs/remote-file-change})))))))
                                                                                                                    :fs/event :fs/remote-file-change})))))))
@@ -1687,7 +1525,7 @@
 
 
                                           ;; else
                                           ;; else
                                             (p/do!
                                             (p/do!
-                                             (fs/write-file! repo repo-dir current-change-file merged-content {:skip-compare? true})
+                                             (fs/write-plain-text-file! repo repo-dir current-change-file merged-content {:skip-compare? true})
                                              (file-handler/alter-file repo current-change-file merged-content {:re-render-root? true
                                              (file-handler/alter-file repo current-change-file merged-content {:re-render-root? true
                                                                                                                :from-disk? true
                                                                                                                :from-disk? true
                                                                                                                :fs/event :fs/remote-file-change})))))))))))))))))
                                                                                                                :fs/event :fs/remote-file-change})))))))))))))))))
@@ -1724,8 +1562,8 @@
                      [recent-remote->local-file-item])
                      [recent-remote->local-file-item])
               (<! (<delete-local-files rsapi graph-uuid base-path [relative-p*]))
               (<! (<delete-local-files rsapi graph-uuid base-path [relative-p*]))
               (go (<! (timeout 5000))
               (go (<! (timeout 5000))
-                (swap! *sync-state sync-state--remove-recent-remote->local-files
-                       [recent-remote->local-file-item])))))
+                  (swap! *sync-state sync-state--remove-recent-remote->local-files
+                         [recent-remote->local-file-item])))))
 
 
         (let [update-local-files-ch (if (state/enable-sync-diff-merge?)
         (let [update-local-files-ch (if (state/enable-sync-diff-merge?)
                                       (<fetch-remote-and-update-local-files graph-uuid base-path (map relative-path filetxns))
                                       (<fetch-remote-and-update-local-files graph-uuid base-path (map relative-path filetxns))
@@ -1781,8 +1619,8 @@
                                                      (not (instance? ExceptionInfo r)))]
                                                      (not (instance? ExceptionInfo r)))]
           ;; remove these recent-remote->local-file-items 5s later
           ;; remove these recent-remote->local-file-items 5s later
           (go (<! (timeout 5000))
           (go (<! (timeout 5000))
-            (swap! *sync-state sync-state--remove-recent-remote->local-files
-                   recent-remote->local-file-items))
+              (swap! *sync-state sync-state--remove-recent-remote->local-files
+                     recent-remote->local-file-items))
           (cond
           (cond
             (instance? ExceptionInfo r) r
             (instance? ExceptionInfo r) r
             @*paused                    {:pause true}
             @*paused                    {:pause true}
@@ -1841,7 +1679,6 @@
   [r]
   [r]
   (some->> (ex-cause r) str (re-find #"Request is not yet valid")))
   (some->> (ex-cause r) str (re-find #"Request is not yet valid")))
 
 
-
 ;; type = "change" | "add" | "unlink"
 ;; type = "change" | "add" | "unlink"
 (deftype FileChangeEvent [type dir path stat checksum]
 (deftype FileChangeEvent [type dir path stat checksum]
   IRelativePath
   IRelativePath
@@ -1876,7 +1713,6 @@
   (-pr-writer [_ w _opts]
   (-pr-writer [_ w _opts]
     (write-all w (str {:type type :base-path dir :path path :size (:size stat) :checksum checksum}))))
     (write-all w (str {:type type :base-path dir :path path :size (:size stat) :checksum checksum}))))
 
 
-
 (defn- <file-change-event=>recent-remote->local-file-item
 (defn- <file-change-event=>recent-remote->local-file-item
   "return nil when related local files not found"
   "return nil when related local files not found"
   [graph-uuid ^FileChangeEvent e]
   [graph-uuid ^FileChangeEvent e]
@@ -1949,8 +1785,8 @@
     (go-loop []
     (go-loop []
       (let [{:keys [rename-event local-change]}
       (let [{:keys [rename-event local-change]}
             (async/alt!
             (async/alt!
-             rename-page-event-chan ([v] {:rename-event v}) ;; {:repo X :old-path X :new-path}
-             local-changes-chan' ([v] {:local-change v}))]
+              rename-page-event-chan ([v] {:rename-event v}) ;; {:repo X :old-path X :new-path}
+              local-changes-chan' ([v] {:local-change v}))]
         (cond
         (cond
           rename-event
           rename-event
           (let [repo-dir (config/get-repo-dir (:repo rename-event))
           (let [repo-dir (config/get-repo-dir (:repo rename-event))
@@ -1963,13 +1799,13 @@
             (swap! *rename-events conj k1 k2)
             (swap! *rename-events conj k1 k2)
             ;; remove rename-events after 2s
             ;; remove rename-events after 2s
             (go (<! (timeout 3000))
             (go (<! (timeout 3000))
-              (swap! *rename-events disj k1 k2))
+                (swap! *rename-events disj k1 k2))
             ;; add 2 simulated file-watcher events
             ;; add 2 simulated file-watcher events
             (>! ch (->FileChangeEvent "unlink" repo-dir (:old-path rename-event*) nil nil))
             (>! ch (->FileChangeEvent "unlink" repo-dir (:old-path rename-event*) nil nil))
             (>! ch (->FileChangeEvent "add" repo-dir (:new-path rename-event*)
             (>! ch (->FileChangeEvent "add" repo-dir (:new-path rename-event*)
                                       {:mtime (tc/to-long (t/now))
                                       {:mtime (tc/to-long (t/now))
                                        :size 1 ; add a fake size
                                        :size 1 ; add a fake size
-                                       } "fake-checksum"))
+                                       }"fake-checksum"))
             (recur))
             (recur))
           local-change
           local-change
           (cond
           (cond
@@ -2046,7 +1882,6 @@
     (js/localStorage.removeItem k))
     (js/localStorage.removeItem k))
   (reset! pwd-map {}))
   (reset! pwd-map {}))
 
 
-
 (defn encrypt+persist-pwd!
 (defn encrypt+persist-pwd!
   "- persist encrypted pwd at local-storage"
   "- persist encrypted pwd at local-storage"
   [pwd graph-uuid]
   [pwd graph-uuid]
@@ -2094,7 +1929,6 @@
       (when (and private-key (string/starts-with? private-key "AGE-SECRET-KEY"))
       (when (and private-key (string/starts-with? private-key "AGE-SECRET-KEY"))
         (set-keys&notify graph-uuid public-key private-key)))))
         (set-keys&notify graph-uuid public-key private-key)))))
 
 
-
 (def <restored-pwd (chan (async/sliding-buffer 1)))
 (def <restored-pwd (chan (async/sliding-buffer 1)))
 (def <restored-pwd-pub (async/pub <restored-pwd :graph-uuid))
 (def <restored-pwd-pub (async/pub <restored-pwd :graph-uuid))
 
 
@@ -2124,7 +1958,6 @@
   (swap! pwd-map dissoc graph-uuid)
   (swap! pwd-map dissoc graph-uuid)
   (remove-pwd! graph-uuid))
   (remove-pwd! graph-uuid))
 
 
-
 (defn- <loop-ensure-pwd&keys
 (defn- <loop-ensure-pwd&keys
   [graph-uuid repo *stopped?]
   [graph-uuid repo *stopped?]
   (let [<restored-pwd-sub-chan (chan 1)]
   (let [<restored-pwd-sub-chan (chan 1)]
@@ -2186,7 +2019,6 @@
                       (clear-pwd! graph-uuid)
                       (clear-pwd! graph-uuid)
                       (recur))))))))))
                       (recur))))))))))
 
 
-
 (defn- <set-env&keys
 (defn- <set-env&keys
   [prod? graph-uuid]
   [prod? graph-uuid]
   (let [{:keys [private-key public-key]} (get @pwd-map graph-uuid)]
   (let [{:keys [private-key public-key]} (get @pwd-map graph-uuid)]
@@ -2241,7 +2073,6 @@
            (fn [_ _ _ _]
            (fn [_ _ _ _]
              (offer! recent-edited-chan true)))
              (offer! recent-edited-chan true)))
 
 
-
 ;;; ### sync state
 ;;; ### sync state
 
 
 (def *resume-state
 (def *resume-state
@@ -2385,7 +2216,6 @@
   (contains? #{::idle ::local->remote ::remote->local ::local->remote-full-sync ::remote->local-full-sync}
   (contains? #{::idle ::local->remote ::remote->local ::local->remote-full-sync ::remote->local-full-sync}
              (:state sync-state)))
              (:state sync-state)))
 
 
-
 ;;; ### remote->local syncer & local->remote syncer
 ;;; ### remote->local syncer & local->remote syncer
 
 
 (defprotocol IRemote->LocalSync
 (defprotocol IRemote->LocalSync
@@ -2641,11 +2471,11 @@
          local-files-meta-map))))
          local-files-meta-map))))
 
 
 (defrecord ^:large-vars/cleanup-todo
 (defrecord ^:large-vars/cleanup-todo
-  Local->RemoteSyncer [user-uuid graph-uuid base-path repo *sync-state remoteapi'
-                       ^:mutable rate *txid *txid-for-get-deletion-log
-                       ^:mutable remote->local-syncer stop-chan *stopped *paused
+ Local->RemoteSyncer [user-uuid graph-uuid base-path repo *sync-state remoteapi'
+                      ^:mutable rate *txid *txid-for-get-deletion-log
+                      ^:mutable remote->local-syncer stop-chan *stopped *paused
                        ;; control chans
                        ;; control chans
-                       private-immediately-local->remote-chan private-recent-edited-chan]
+                      private-immediately-local->remote-chan private-recent-edited-chan]
   Object
   Object
   (filter-file-change-events-fn [_]
   (filter-file-change-events-fn [_]
     (fn [^FileChangeEvent e]
     (fn [^FileChangeEvent e]
@@ -2812,21 +2642,21 @@
                                             <!
                                             <!
                                             (sort-by (sort-file-metadata-fn :recent-days-range recent-10-days-range) >))
                                             (sort-by (sort-file-metadata-fn :recent-days-range recent-10-days-range) >))
                 change-events
                 change-events
-                                       (sequence
-                                        (comp
+                (sequence
+                 (comp
                                          ;; convert to FileChangeEvent
                                          ;; convert to FileChangeEvent
-                                         (map #(->FileChangeEvent "change" base-path (.get-normalized-path ^FileMetadata %)
-                                                                  {:size (:size %)} (:etag %)))
-                                         (remove ignored?))
-                                        diff-local-files)
+                  (map #(->FileChangeEvent "change" base-path (.get-normalized-path ^FileMetadata %)
+                                           {:size (:size %)} (:etag %)))
+                  (remove ignored?))
+                 diff-local-files)
                 distinct-change-events (-> (distinct-file-change-events change-events)
                 distinct-change-events (-> (distinct-file-change-events change-events)
                                            filter-upload-files-with-reserved-chars)
                                            filter-upload-files-with-reserved-chars)
                 _                      (swap! *sync-state #(sync-state-reset-full-local->remote-files % distinct-change-events))
                 _                      (swap! *sync-state #(sync-state-reset-full-local->remote-files % distinct-change-events))
                 change-events-partitions
                 change-events-partitions
-                                       (sequence
+                (sequence
                                         ;; partition FileChangeEvents
                                         ;; partition FileChangeEvents
-                                        (partition-file-change-events upload-batch-size)
-                                        distinct-change-events)]
+                 (partition-file-change-events upload-batch-size)
+                 distinct-change-events)]
             (println "[full-sync(local->remote)]"
             (println "[full-sync(local->remote)]"
                      (count (flatten change-events-partitions)) "files need to sync and"
                      (count (flatten change-events-partitions)) "files need to sync and"
                      (count delete-local-files) "local files need to delete")
                      (count delete-local-files) "local files need to delete")
@@ -2847,8 +2677,8 @@
                              [fake-recent-remote->local-file-item])
                              [fake-recent-remote->local-file-item])
                       (<! (<delete-local-files rsapi graph-uuid base-path [(relative-path f)]))
                       (<! (<delete-local-files rsapi graph-uuid base-path [(relative-path f)]))
                       (go (<! (timeout 5000))
                       (go (<! (timeout 5000))
-                        (swap! *sync-state sync-state--remove-recent-remote->local-files
-                               [fake-recent-remote->local-file-item])))))
+                          (swap! *sync-state sync-state--remove-recent-remote->local-files
+                                 [fake-recent-remote->local-file-item])))))
                 (recur fs)))
                 (recur fs)))
 
 
             ;; 2. upload local files
             ;; 2. upload local files
@@ -2866,13 +2696,12 @@
                               (or need-sync-remote graph-has-been-deleted unknown stop) r)))))]
                               (or need-sync-remote graph-has-been-deleted unknown stop) r)))))]
               ;; update *txid-for-get-deletion-log
               ;; update *txid-for-get-deletion-log
               (reset! *txid-for-get-deletion-log @*txid)
               (reset! *txid-for-get-deletion-log @*txid)
-              r
-              )))))))
+              r)))))))
 
 
 ;;; ### put all stuff together
 ;;; ### put all stuff together
 
 
 (defrecord ^:large-vars/cleanup-todo
 (defrecord ^:large-vars/cleanup-todo
-    SyncManager [user-uuid graph-uuid base-path *sync-state
+ SyncManager [user-uuid graph-uuid base-path *sync-state
               ^Local->RemoteSyncer local->remote-syncer ^Remote->LocalSyncer remote->local-syncer remoteapi'
               ^Local->RemoteSyncer local->remote-syncer ^Remote->LocalSyncer remote->local-syncer remoteapi'
               ^:mutable ratelimit-local-changes-chan
               ^:mutable ratelimit-local-changes-chan
               *txid *txid-for-get-deletion-log
               *txid *txid-for-get-deletion-log
@@ -3256,9 +3085,7 @@
         local->remote-syncer (->Local->RemoteSyncer user-uuid graph-uuid
         local->remote-syncer (->Local->RemoteSyncer user-uuid graph-uuid
                                                     base-path
                                                     base-path
                                                     repo *sync-state remoteapi-with-stop
                                                     repo *sync-state remoteapi-with-stop
-                                                    (if (mobile-util/native-platform?)
-                                                      2000
-                                                      10000)
+                                                    10000
                                                     *txid *txid-for-get-deletion-log nil (chan) *stopped? *paused?
                                                     *txid *txid-for-get-deletion-log nil (chan) *stopped? *paused?
                                                     (chan 1) (chan 1))
                                                     (chan 1) (chan 1))
         remote->local-syncer (->Remote->LocalSyncer user-uuid graph-uuid base-path
         remote->local-syncer (->Remote->LocalSyncer user-uuid graph-uuid base-path
@@ -3276,7 +3103,6 @@
     (reset! current-sm-graph-uuid graph-uuid)
     (reset! current-sm-graph-uuid graph-uuid)
     (sync-manager user-uuid graph-uuid base-path repo txid *sync-state)))
     (sync-manager user-uuid graph-uuid base-path repo txid *sync-state)))
 
 
-
 (defn <sync-stop []
 (defn <sync-stop []
   (go
   (go
     (when-let [sm ^SyncManager (state/get-file-sync-manager (state/get-current-file-sync-graph-uuid))]
     (when-let [sm ^SyncManager (state/get-file-sync-manager (state/get-current-file-sync-graph-uuid))]
@@ -3290,11 +3116,6 @@
 
 
     (reset! current-sm-graph-uuid nil)))
     (reset! current-sm-graph-uuid nil)))
 
 
-(defn <sync-local->remote-now []
-  (go
-    (when-let [_sm ^SyncManager (state/get-file-sync-manager (state/get-current-file-sync-graph-uuid))]
-      (offer! immediately-local->remote-chan true))))
-
 (defn sync-need-password!
 (defn sync-need-password!
   []
   []
   (when-let [sm ^SyncManager (state/get-file-sync-manager (state/get-current-file-sync-graph-uuid))]
   (when-let [sm ^SyncManager (state/get-file-sync-manager (state/get-current-file-sync-graph-uuid))]
@@ -3319,15 +3140,15 @@
   (go
   (go
     (let [r (<! (<list-remote-graphs remoteapi))
     (let [r (<! (<list-remote-graphs remoteapi))
           result
           result
-            (or
+          (or
              ;; if api call failed, assume this remote graph still exists
              ;; if api call failed, assume this remote graph still exists
-             (instance? ExceptionInfo r)
-             (and
-              (contains? r :Graphs)
-              (->> (:Graphs r)
-                   (mapv :GraphUUID)
-                   set
-                   (#(contains? % local-graph-uuid)))))]
+           (instance? ExceptionInfo r)
+           (and
+            (contains? r :Graphs)
+            (->> (:Graphs r)
+                 (mapv :GraphUUID)
+                 set
+                 (#(contains? % local-graph-uuid)))))]
 
 
       (when-not result
       (when-not result
         (notification/show! (t :file-sync/graph-deleted) :warning false))
         (notification/show! (t :file-sync/graph-deleted) :warning false))
@@ -3347,7 +3168,6 @@
   (when-let [graph-uuid (second @graphs-txid)]
   (when-let [graph-uuid (second @graphs-txid)]
     (get-pwd graph-uuid)))
     (get-pwd graph-uuid)))
 
 
-
 (defn- <connectivity-testing
 (defn- <connectivity-testing
   []
   []
   (go
   (go
@@ -3441,52 +3261,8 @@
           (finally
           (finally
             (reset! *sync-starting false)))))))
             (reset! *sync-starting false)))))))
 
 
-(defn- restart-if-stopped!
-  [is-active?]
-  (cond
-    (and is-active? (graph-sync-off? (second @graphs-txid)))
-    (<sync-start)
-
-    :else
-    (offer! pause-resume-chan is-active?)))
-
-(def app-state-changed-cursor (rum/cursor state/state :mobile/app-state-change))
-
 (def finished-local->remote-chan (chan 1))
 (def finished-local->remote-chan (chan 1))
 
 
-(add-watch app-state-changed-cursor "sync"
-           (fn [_ _ _ {:keys [is-active?]}]
-             (cond
-               (mobile-util/native-android?)
-               (when-not is-active?
-                 (<sync-local->remote-now))
-
-               (mobile-util/native-ios?)
-               (let [*task-id (atom nil)]
-                 (if is-active?
-                   (restart-if-stopped! is-active?)
-                   (when (state/get-current-file-sync-graph-uuid)
-                     (p/let [task-id (.beforeExit ^js BackgroundTask
-                                                  (fn []
-                                                    (go
-                                                      ;; Wait for file watcher events
-                                                      (<! (timeout 2000))
-                                                      (util/drain-chan finished-local->remote-chan)
-                                                      (<! (<sync-local->remote-now))
-                                                      ;; wait at most 20s
-                                                      (async/alts! [finished-local->remote-chan (timeout 20000)])
-                                                      (p/let [active? (mobile-util/app-active?)]
-                                                        (when-not active?
-                                                          (offer! pause-resume-chan is-active?)))
-                                                      (<! (timeout 5000))
-                                                      (prn "finish task: " @*task-id)
-                                                      (let [opt #js {:taskId @*task-id}]
-                                                        (.finish ^js BackgroundTask opt)))))]
-                       (reset! *task-id task-id)))))
-
-               :else
-               nil)))
-
 ;;; ### some add-watches
 ;;; ### some add-watches
 
 
 ;; TODO: replace this logic by pause/resume state
 ;; TODO: replace this logic by pause/resume state
@@ -3517,7 +3293,6 @@
     (<sync-start))
     (<sync-start))
   (recur))
   (recur))
 
 
-
 ;;; ### some sync events handler
 ;;; ### some sync events handler
 
 
 ;; re-exec remote->local-full-sync when it failed before
 ;; re-exec remote->local-full-sync when it failed before
@@ -3543,6 +3318,5 @@
 
 
 ;;; add-tap
 ;;; add-tap
 (comment
 (comment
- (def *x (atom nil))
- (add-tap (fn [v] (reset! *x v)))
- )
+  (def *x (atom nil))
+  (add-tap (fn [v] (reset! *x v))))

+ 0 - 5
src/main/frontend/handler.cljs

@@ -30,7 +30,6 @@
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.user :as user-handler]
             [frontend.handler.user :as user-handler]
             [frontend.idb :as idb]
             [frontend.idb :as idb]
-            [frontend.mobile.core :as mobile]
             [frontend.mobile.util :as mobile-util]
             [frontend.mobile.util :as mobile-util]
             [frontend.modules.instrumentation.core :as instrument]
             [frontend.modules.instrumentation.core :as instrument]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.modules.shortcut.core :as shortcut]
@@ -92,8 +91,6 @@
          (fn []
          (fn []
            (js/console.log "db restored, setting up repo hooks")
            (js/console.log "db restored, setting up repo hooks")
 
 
-           (state/pub-event! [:modal/nfs-ask-permission])
-
            (page-handler/init-commands!)
            (page-handler/init-commands!)
 
 
            (watch-for-date!)
            (watch-for-date!)
@@ -169,8 +166,6 @@
   (events/run!)
   (events/run!)
 
 
   (p/do!
   (p/do!
-   (when (mobile-util/native-platform?)
-     (mobile/mobile-preinit))
    (-> (p/let [_ (db-browser/start-db-worker!)
    (-> (p/let [_ (db-browser/start-db-worker!)
                repos (repo-handler/get-repos)
                repos (repo-handler/get-repos)
                _ (state/set-repos! repos)
                _ (state/set-repos! repos)

+ 2 - 19
src/main/frontend/handler/assets.cljs

@@ -5,7 +5,6 @@
             [frontend.common.thread-api :as thread-api :refer [def-thread-api]]
             [frontend.common.thread-api :as thread-api :refer [def-thread-api]]
             [frontend.config :as config]
             [frontend.config :as config]
             [frontend.fs :as fs]
             [frontend.fs :as fs]
-            [frontend.fs.nfs :as nfs]
             [frontend.mobile.util :as mobile-util]
             [frontend.mobile.util :as mobile-util]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.util :as util]
             [frontend.util :as util]
@@ -155,8 +154,6 @@
               css
               css
               (map vector rel-paths blob-urls)))))
               (map vector rel-paths blob-urls)))))
 
 
-(defonce *assets-url-cache (atom {}))
-
 (defn <make-asset-url
 (defn <make-asset-url
   "Make asset URL for UI element, to fill img.src"
   "Make asset URL for UI element, to fill img.src"
   [path] ;; path start with "/assets"(editor) or compatible for "../assets"(whiteboards)
   [path] ;; path start with "/assets"(editor) or compatible for "../assets"(whiteboards)
@@ -187,21 +184,7 @@
         (config/db-based-graph? (state/get-current-repo)) ; memory fs
         (config/db-based-graph? (state/get-current-repo)) ; memory fs
         (p/let [binary (fs/read-file repo-dir path {})
         (p/let [binary (fs/read-file repo-dir path {})
                 blob (js/Blob. (array binary) (clj->js {:type "image"}))]
                 blob (js/Blob. (array binary) (clj->js {:type "image"}))]
-          (when blob (js/URL.createObjectURL blob)))
-
-        :else ;; nfs
-        (let [handle-path (str "handle/" full-path)
-              cached-url  (get @*assets-url-cache (keyword handle-path))]
-          (if cached-url
-            (p/resolved cached-url)
-            ;; Loading File from handle cache
-            ;; Use await file handle, to ensure all handles are loaded.
-            (p/let [handle (nfs/await-get-nfs-file-handle repo handle-path)
-                    file   (and handle (.getFile handle))]
-              (when file
-                (p/let [url (js/URL.createObjectURL file)]
-                  (swap! *assets-url-cache assoc (keyword handle-path) url)
-                  url)))))))))
+          (when blob (js/URL.createObjectURL blob)))))))
 
 
 (defn- decode-digest
 (defn- decode-digest
   [^js/Uint8Array digest]
   [^js/Uint8Array digest]
@@ -266,7 +249,7 @@
         repo-dir (config/get-repo-dir repo)
         repo-dir (config/get-repo-dir repo)
         file-path (path/path-join common-config/local-assets-dir
         file-path (path/path-join common-config/local-assets-dir
                                   (str asset-block-id-str "." asset-type))]
                                   (str asset-block-id-str "." asset-type))]
-    (fs/write-file! repo repo-dir file-path data {})))
+    (fs/write-plain-text-file! repo repo-dir file-path data {})))
 
 
 (defn <unlink-asset
 (defn <unlink-asset
   [repo asset-block-id asset-type]
   [repo asset-block-id asset-type]

+ 2 - 1
src/main/frontend/handler/db_based/rtc_flows.cljs

@@ -142,5 +142,6 @@ conditions:
      (map vector)
      (map vector)
      network-online&rtc-not-running-flow)]
      network-online&rtc-not-running-flow)]
    (apply c.m/mix)
    (apply c.m/mix)
-   (m/eduction (filter (fn [_] (some? (state/get-auth-id-token)))))
+   (m/latest vector flows/current-login-user-flow)
+   (m/eduction (keep (fn [[current-user trigger-event]] (when current-user trigger-event))))
    (c.m/debounce 200)))
    (c.m/debounce 200)))

+ 1 - 1
src/main/frontend/handler/dnd.cljs

@@ -6,7 +6,7 @@
             [frontend.handler.property :as property-handler]
             [frontend.handler.property :as property-handler]
             [frontend.modules.outliner.op :as outliner-op]
             [frontend.modules.outliner.op :as outliner-op]
             [frontend.modules.outliner.ui :as ui-outliner-tx]
             [frontend.modules.outliner.ui :as ui-outliner-tx]
-            [frontend.ref :as ref]
+            [frontend.util.ref :as ref]
             [frontend.state :as state]
             [frontend.state :as state]
             [logseq.db :as ldb]))
             [logseq.db :as ldb]))
 
 

+ 12 - 10
src/main/frontend/handler/draw.cljs

@@ -25,16 +25,18 @@
   (let [path file
   (let [path file
         repo (state/get-current-repo)]
         repo (state/get-current-repo)]
     (when repo
     (when repo
-      (->
-       (p/do!
-        (create-draws-directory! repo)
-        (db/transact! repo
-                      [{:file/path path
-                        :block/name (util/page-name-sanity-lc file)
-                        :block/file {:file/path path}}]))
-       (p/catch (fn [error]
-                  (prn "Write file failed, path: " path ", data: " data)
-                  (js/console.dir error)))))))
+      (let [repo-dir (config/get-repo-dir repo)]
+        (->
+         (p/do!
+          (create-draws-directory! repo)
+          (fs/write-plain-text-file! repo repo-dir path data nil)
+          (db/transact! repo
+                        [{:file/path path
+                          :block/name (util/page-name-sanity-lc file)
+                          :block/file {:file/path path}}]))
+         (p/catch (fn [error]
+                    (prn "Write file failed, path: " path ", data: " data)
+                    (js/console.dir error))))))))
 
 
 (defn load-excalidraw-file
 (defn load-excalidraw-file
   [file ok-handler]
   [file ok-handler]

+ 17 - 36
src/main/frontend/handler/editor.cljs

@@ -3,6 +3,7 @@
             [clojure.string :as string]
             [clojure.string :as string]
             [clojure.walk :as w]
             [clojure.walk :as w]
             [dommy.core :as dom]
             [dommy.core :as dom]
+            [electron.ipc :as ipc]
             [frontend.commands :as commands]
             [frontend.commands :as commands]
             [frontend.config :as config]
             [frontend.config :as config]
             [frontend.date :as date]
             [frontend.date :as date]
@@ -16,7 +17,6 @@
             [frontend.format.block :as block]
             [frontend.format.block :as block]
             [frontend.format.mldoc :as mldoc]
             [frontend.format.mldoc :as mldoc]
             [frontend.fs :as fs]
             [frontend.fs :as fs]
-            [frontend.fs.capacitor-fs :as capacitor-fs]
             [frontend.handler.assets :as assets-handler]
             [frontend.handler.assets :as assets-handler]
             [frontend.handler.block :as block-handler]
             [frontend.handler.block :as block-handler]
             [frontend.handler.common :as common-handler]
             [frontend.handler.common :as common-handler]
@@ -35,7 +35,7 @@
             [frontend.modules.outliner.op :as outliner-op]
             [frontend.modules.outliner.op :as outliner-op]
             [frontend.modules.outliner.tree :as tree]
             [frontend.modules.outliner.tree :as tree]
             [frontend.modules.outliner.ui :as ui-outliner-tx]
             [frontend.modules.outliner.ui :as ui-outliner-tx]
-            [frontend.ref :as ref]
+            [frontend.util.ref :as ref]
             [frontend.search :as search]
             [frontend.search :as search]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.template :as template]
             [frontend.template :as template]
@@ -46,7 +46,6 @@
             [frontend.util.list :as list]
             [frontend.util.list :as list]
             [frontend.util.text :as text-util]
             [frontend.util.text :as text-util]
             [frontend.util.thingatpt :as thingatpt]
             [frontend.util.thingatpt :as thingatpt]
-            [goog.crypt.base64 :as base64]
             [goog.dom :as gdom]
             [goog.dom :as gdom]
             [goog.dom.classes :as gdom-classes]
             [goog.dom.classes :as gdom-classes]
             [goog.object :as gobj]
             [goog.object :as gobj]
@@ -1054,6 +1053,8 @@
   (state/set-block-op-type! :cut)
   (state/set-block-op-type! :cut)
   (when-let [blocks (->> (get-selected-blocks)
   (when-let [blocks (->> (get-selected-blocks)
                          (remove #(dom/has-class? % "property-value-container"))
                          (remove #(dom/has-class? % "property-value-container"))
+                         (remove (fn [block] (or (= "true" (dom/attr block "data-query"))
+                                                 (= "true" (dom/attr block "data-transclude")))))
                          seq)]
                          seq)]
     ;; remove queries
     ;; remove queries
     (let [dom-blocks (remove (fn [block] (= "true" (dom/attr block "data-query"))) blocks)]
     (let [dom-blocks (remove (fn [block] (= "true" (dom/attr block "data-query"))) blocks)]
@@ -1382,8 +1383,6 @@
              (property-file/remove-properties-when-file-based repo format)
              (property-file/remove-properties-when-file-based repo format)
              string/trim)))
              string/trim)))
 
 
-(def insert-command! editor-common-handler/insert-command!)
-
 (defn delete-asset-of-block!
 (defn delete-asset-of-block!
   [{:keys [repo asset-block href full-text block-id local? delete-local?] :as _opts}]
   [{:keys [repo asset-block href full-text block-id local? delete-local?] :as _opts}]
   (let [block (db-model/query-block-by-uuid block-id)
   (let [block (db-model/query-block-by-uuid block-id)
@@ -1407,36 +1406,16 @@
                                (path/resolve-relative-path block-file-rpath href)))]
                                (path/resolve-relative-path block-file-rpath href)))]
             (fs/unlink! repo asset-fpath nil)))))))
             (fs/unlink! repo asset-fpath nil)))))))
 
 
-(defn- write-file!
-  [repo dir file file-rpath file-name]
-  (if (util/electron?)
-    (if-let [from (not-empty (.-path file))]
-      (-> (js/window.apis.copyFileToAssets dir file-rpath from)
-          (p/catch #(js/console.error "Debug: Copy Asset Error#" %)))
-      (-> (p/let [buffer (.arrayBuffer file)]
-            (fs/write-file! repo dir file-rpath buffer {:skip-compare? false}))
-          (p/catch #(js/console.error "Debug: Writing Asset #" %))))
-    (->
-     (p/do! (js/console.debug "Debug: Writing Asset #" dir file-rpath)
-            (cond
-              (mobile-util/native-platform?)
-                          ;; capacitor fs accepts Blob, File implements Blob
-              (p/let [buffer (.arrayBuffer file)
-                      content (base64/encodeByteArray (js/Uint8Array. buffer))
-                      fpath (path/path-join dir file-rpath)]
-                (capacitor-fs/<write-file-with-base64 fpath content))
-
-              (config/db-based-graph? repo) ;; memory-fs
-              (p/let [buffer (.arrayBuffer file)
-                      content (js/Uint8Array. buffer)]
-                (fs/write-file! repo dir file-rpath content nil))
-
-              :else
-              (throw (ex-info "Paste failed"
-                              {:file-name file-name}))))
-     (p/catch (fn [error]
-                (prn :paste-file-error)
-                (js/console.error error))))))
+(defn db-based-save-asset!
+  [repo dir file file-rpath]
+  (p/let [buffer (.arrayBuffer file)]
+    (if (util/electron?)
+      (ipc/ipc "writeFile" repo (path/path-join dir file-rpath) buffer)
+      ;; web
+      (p/let [buffer (.arrayBuffer file)
+              content (js/Uint8Array. buffer)]
+        ;; actually, writing binary using memory fs
+        (fs/write-plain-text-file! repo dir file-rpath content nil)))))
 
 
 (defn db-based-save-assets!
 (defn db-based-save-assets!
   "Save incoming(pasted) assets to assets directory.
   "Save incoming(pasted) assets to assets directory.
@@ -1470,7 +1449,7 @@
                    insert-opts {:custom-uuid block-id
                    insert-opts {:custom-uuid block-id
                                 :edit-block? false
                                 :edit-block? false
                                 :properties properties}
                                 :properties properties}
-                   _ (write-file! repo dir file file-rpath file-name)
+                   _ (db-based-save-asset! repo dir file file-rpath)
                    edit-block (state/get-edit-block)
                    edit-block (state/get-edit-block)
                    insert-to-current-block-page? (and (:block/uuid edit-block) (string/blank? (state/get-edit-content)) (not pdf-area?))
                    insert-to-current-block-page? (and (:block/uuid edit-block) (string/blank? (state/get-edit-content)) (not pdf-area?))
                    insert-opts' (if insert-to-current-block-page?
                    insert-opts' (if insert-to-current-block-page?
@@ -1486,6 +1465,8 @@
              (or new-entity
              (or new-entity
                  (throw (ex-info "Can't save asset" {:files files}))))))))))
                  (throw (ex-info "Can't save asset" {:files files}))))))))))
 
 
+(def insert-command! editor-common-handler/insert-command!)
+
 (defn db-upload-assets!
 (defn db-upload-assets!
   "Paste asset for db graph and insert link to current editing block"
   "Paste asset for db graph and insert link to current editing block"
   [repo id ^js files format uploading? drop-or-paste?]
   [repo id ^js files format uploading? drop-or-paste?]

+ 13 - 85
src/main/frontend/handler/events.cljs

@@ -3,8 +3,7 @@
   core.async channel to handle them. Any part of the system can dispatch
   core.async channel to handle them. Any part of the system can dispatch
   one of these events using state/pub-event!"
   one of these events using state/pub-event!"
   (:refer-clojure :exclude [run!])
   (:refer-clojure :exclude [run!])
-  (:require ["@capacitor/filesystem" :refer [Directory Filesystem]]
-            ["@sentry/react" :as Sentry]
+  (:require ["@sentry/react" :as Sentry]
             [cljs-bean.core :as bean]
             [cljs-bean.core :as bean]
             [clojure.core.async :as async]
             [clojure.core.async :as async]
             [clojure.core.async.interop :refer [p->c]]
             [clojure.core.async.interop :refer [p->c]]
@@ -14,9 +13,7 @@
             [frontend.date :as date]
             [frontend.date :as date]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.db.async :as db-async]
             [frontend.db.async :as db-async]
-            [frontend.db.conn :as conn]
             [frontend.db.model :as db-model]
             [frontend.db.model :as db-model]
-            [frontend.db.persist :as db-persist]
             [frontend.db.transact :as db-transact]
             [frontend.db.transact :as db-transact]
             [frontend.extensions.fsrs :as fsrs]
             [frontend.extensions.fsrs :as fsrs]
             [frontend.fs :as fs]
             [frontend.fs :as fs]
@@ -30,7 +27,6 @@
             [frontend.handler.db-based.rtc-flows :as rtc-flows]
             [frontend.handler.db-based.rtc-flows :as rtc-flows]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.export :as export]
             [frontend.handler.export :as export]
-            [frontend.handler.file-sync :as file-sync-handler]
             [frontend.handler.graph :as graph-handler]
             [frontend.handler.graph :as graph-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
             [frontend.handler.page :as page-handler]
             [frontend.handler.page :as page-handler]
@@ -49,7 +45,6 @@
             [frontend.modules.shortcut.core :as st]
             [frontend.modules.shortcut.core :as st]
             [frontend.persist-db :as persist-db]
             [frontend.persist-db :as persist-db]
             [frontend.quick-capture :as quick-capture]
             [frontend.quick-capture :as quick-capture]
-            [frontend.search :as search]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.util :as util]
             [frontend.util :as util]
             [frontend.util.persist-var :as persist-var]
             [frontend.util.persist-var :as persist-var]
@@ -85,29 +80,22 @@
   (when (= (:url repo) current-repo)
   (when (= (:url repo) current-repo)
     (file-sync-restart!)))
     (file-sync-restart!)))
 
 
-;; FIXME(andelf): awful multi-arty function.
-;; Should use a `-impl` function instead of the awful `skip-ios-check?` param with nested callback.
 (defn- graph-switch
 (defn- graph-switch
-  ([graph]
-   (graph-switch graph false))
-  ([graph skip-ios-check?]
-   (let [db-based? (config/db-based-graph? graph)]
-     (if (and (mobile-util/native-ios?) (not skip-ios-check?))
-       (state/pub-event! [:validate-appId graph-switch graph])
-       (do
-         (state/set-current-repo! graph)
-         (page-handler/init-commands!)
+  [graph]
+  (let [db-based? (config/db-based-graph? graph)]
+    (state/set-current-repo! graph)
+    (page-handler/init-commands!)
          ;; load config
          ;; load config
-         (repo-config-handler/restore-repo-config! graph)
-         (when-not (= :draw (state/get-current-route))
-           (route-handler/redirect-to-home!))
-         (when-not db-based?
+    (repo-config-handler/restore-repo-config! graph)
+    (when-not (= :draw (state/get-current-route))
+      (route-handler/redirect-to-home!))
+    (when-not db-based?
            ;; graph-switch will trigger a rtc-start automatically
            ;; graph-switch will trigger a rtc-start automatically
            ;; (rtc-handler/<rtc-start! graph)
            ;; (rtc-handler/<rtc-start! graph)
-           (file-sync-restart!))
-         (when-let [dir-name (and (not db-based?) (config/get-repo-dir graph))]
-           (fs/watch-dir! dir-name))
-         (graph-handler/settle-metadata-to-local! {:last-seen-at (js/Date.now)}))))))
+      (file-sync-restart!))
+    (when-let [dir-name (and (not db-based?) (config/get-repo-dir graph))]
+      (fs/watch-dir! dir-name))
+    (graph-handler/settle-metadata-to-local! {:last-seen-at (js/Date.now)})))
 
 
 ;; Parameters for the `persist-db` function, to show the notification messages
 ;; Parameters for the `persist-db` function, to show the notification messages
 (defn- graph-switch-on-persisted
 (defn- graph-switch-on-persisted
@@ -271,72 +259,12 @@
       (when-let [toolbar (.querySelector main-node "#mobile-editor-toolbar")]
       (when-let [toolbar (.querySelector main-node "#mobile-editor-toolbar")]
         (set! (.. toolbar -style -bottom) 0)))))
         (set! (.. toolbar -style -bottom) 0)))))
 
 
-(defn- get-ios-app-id
-  [repo-url]
-  (when repo-url
-    (let [app-id (-> (first (string/split repo-url "/Documents"))
-                     (string/split "/")
-                     last)]
-      app-id)))
-
-(defmethod handle :validate-appId [[_ graph-switch-f graph]]
-  (when-let [deprecated-repo (or graph (state/get-current-repo))]
-    (if (mobile-util/in-iCloud-container-path? deprecated-repo)
-      ;; Installation is not changed for iCloud
-      (when graph-switch-f
-        (graph-switch-f graph true)
-        (state/pub-event! [:graph/ready (state/get-current-repo)]))
-      ;; Installation is changed for App Documents directory
-      (p/let [deprecated-app-id (get-ios-app-id deprecated-repo)
-              current-document-url (.getUri Filesystem #js {:path ""
-                                                            :directory (.-Documents Directory)})
-              current-app-id (-> (js->clj current-document-url :keywordize-keys true)
-                                 get-ios-app-id)]
-        (if (= deprecated-app-id current-app-id)
-          (when graph-switch-f (graph-switch-f graph true))
-          (do
-            (notification/show! [:div "Migrating from previous App installation..."]
-                                :warning
-                                true)
-            (prn ::migrate-app-id :from deprecated-app-id :to current-app-id)
-            (file-sync-stop!)
-            (.unwatch mobile-util/fs-watcher)
-            (let [current-repo (string/replace deprecated-repo deprecated-app-id current-app-id)
-                  current-repo-dir (config/get-repo-dir current-repo)]
-              (try
-                ;; replace app-id part of repo url
-                (reset! conn/conns
-                        (update-keys @conn/conns
-                                     (fn [key]
-                                       (if (string/includes? key deprecated-app-id)
-                                         (string/replace key deprecated-app-id current-app-id)
-                                         key))))
-                (db-persist/rename-graph! deprecated-repo current-repo)
-                (search/remove-db! deprecated-repo)
-                (state/add-repo! {:url current-repo :nfs? true})
-                (state/delete-repo! {:url deprecated-repo})
-                (catch :default e
-                  (js/console.error e)))
-              (state/set-current-repo! current-repo)
-              (repo-config-handler/restore-repo-config! current-repo)
-              (when graph-switch-f (graph-switch-f current-repo true))
-              (.watch mobile-util/fs-watcher #js {:path current-repo-dir})
-              (file-sync-restart!))))
-        (state/pub-event! [:graph/ready (state/get-current-repo)])))))
-
 (defmethod handle :plugin/hook-db-tx [[_ {:keys [blocks tx-data] :as payload}]]
 (defmethod handle :plugin/hook-db-tx [[_ {:keys [blocks tx-data] :as payload}]]
   (when-let [payload (and (seq blocks)
   (when-let [payload (and (seq blocks)
                           (merge payload {:tx-data (map #(into [] %) tx-data)}))]
                           (merge payload {:tx-data (map #(into [] %) tx-data)}))]
     (plugin-handler/hook-plugin-db :changed payload)
     (plugin-handler/hook-plugin-db :changed payload)
     (plugin-handler/hook-plugin-block-changes payload)))
     (plugin-handler/hook-plugin-block-changes payload)))
 
 
-(defmethod handle :mobile-file-watcher/changed [[_ ^js event]]
-  (let [type (.-event event)
-        payload (js->clj event :keywordize-keys true)]
-    (fs-watcher/handle-changed! type payload)
-    (when (file-sync-handler/enable-sync?)
-      (sync/file-watch-handler type payload))))
-
 (defmethod handle :rebuild-slash-commands-list [[_]]
 (defmethod handle :rebuild-slash-commands-list [[_]]
   (page-handler/rebuild-slash-commands-list!))
   (page-handler/rebuild-slash-commands-list!))
 
 

+ 1 - 38
src/main/frontend/handler/events/ui.cljs

@@ -19,13 +19,11 @@
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.extensions.fsrs :as fsrs]
             [frontend.extensions.fsrs :as fsrs]
             [frontend.extensions.srs :as srs]
             [frontend.extensions.srs :as srs]
-            [frontend.fs.capacitor-fs :as capacitor-fs]
-            [frontend.fs.nfs :as nfs]
             [frontend.fs.sync :as sync]
             [frontend.fs.sync :as sync]
             [frontend.handler.db-based.rtc :as rtc-handler]
             [frontend.handler.db-based.rtc :as rtc-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.events :as events]
             [frontend.handler.events :as events]
-            [frontend.handler.file-based.nfs :as nfs-handler]
+            [frontend.handler.file-based.native-fs :as nfs-handler]
             [frontend.handler.file-sync :as file-sync-handler]
             [frontend.handler.file-sync :as file-sync-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
             [frontend.handler.page :as page-handler]
             [frontend.handler.page :as page-handler]
@@ -93,35 +91,6 @@
   (shui/dialog-open!
   (shui/dialog-open!
    (component-page/batch-delete-dialog selected-rows ok-handler)))
    (component-page/batch-delete-dialog selected-rows ok-handler)))
 
 
-(defn ask-permission
-  [repo]
-  (when
-   (and (not (util/electron?))
-        (not (mobile-util/native-platform?)))
-    (fn [{:keys [close]}]
-      [:div
-       ;; TODO: fn translation with args
-       [:p
-        "Grant native filesystem permission for directory: "
-        [:b (config/get-local-dir repo)]]
-       (ui/button
-        (t :settings-permission/start-granting)
-        :class "ui__modal-enter"
-        :on-click (fn []
-                    (nfs/check-directory-permission! repo)
-                    (close)))])))
-
-(defn get-local-repo
-  []
-  (when-let [repo (state/get-current-repo)]
-    (when (config/local-file-based-graph? repo)
-      repo)))
-
-(defmethod events/handle :modal/nfs-ask-permission []
-  (when-let [repo (get-local-repo)]
-    (some-> (ask-permission repo)
-            (shui/dialog-open! {:align :top}))))
-
 (defmethod events/handle :modal/show-cards [[_ cards-id]]
 (defmethod events/handle :modal/show-cards [[_ cards-id]]
   (let [db-based? (config/db-based-graph? (state/get-current-repo))]
   (let [db-based? (config/db-based-graph? (state/get-current-repo))]
     (shui/dialog-open!
     (shui/dialog-open!
@@ -129,12 +98,6 @@
      {:id :srs
      {:id :srs
       :label "flashcards__cp"})))
       :label "flashcards__cp"})))
 
 
-(defmethod events/handle :modal/show-instruction [_]
-  (shui/dialog-open!
-   capacitor-fs/instruction
-   {:id :instruction
-    :label "instruction__cp"}))
-
 (defmethod events/handle :modal/show-themes-modal [[_ classic?]]
 (defmethod events/handle :modal/show-themes-modal [[_ classic?]]
   (if classic?
   (if classic?
     (plugin/open-select-theme!)
     (plugin/open-select-theme!)

+ 22 - 48
src/main/frontend/handler/file_based/editor.cljs

@@ -1,6 +1,7 @@
 (ns frontend.handler.file-based.editor
 (ns frontend.handler.file-based.editor
   "File-based graph implementation"
   "File-based graph implementation"
   (:require [clojure.string :as string]
   (:require [clojure.string :as string]
+            [electron.ipc :as ipc]
             [frontend.commands :as commands]
             [frontend.commands :as commands]
             [frontend.config :as config]
             [frontend.config :as config]
             [frontend.date :as date]
             [frontend.date :as date]
@@ -9,8 +10,6 @@
             [frontend.db.query-dsl :as query-dsl]
             [frontend.db.query-dsl :as query-dsl]
             [frontend.format.block :as block]
             [frontend.format.block :as block]
             [frontend.format.mldoc :as mldoc]
             [frontend.format.mldoc :as mldoc]
-            [frontend.fs :as fs]
-            [frontend.fs.capacitor-fs :as capacitor-fs]
             [frontend.handler.assets :as assets-handler]
             [frontend.handler.assets :as assets-handler]
             [frontend.handler.block :as block-handler]
             [frontend.handler.block :as block-handler]
             [frontend.handler.common.editor :as editor-common-handler]
             [frontend.handler.common.editor :as editor-common-handler]
@@ -19,14 +18,12 @@
             [frontend.handler.file-based.repeated :as repeated]
             [frontend.handler.file-based.repeated :as repeated]
             [frontend.handler.file-based.status :as status]
             [frontend.handler.file-based.status :as status]
             [frontend.handler.property.file :as property-file]
             [frontend.handler.property.file :as property-file]
-            [frontend.mobile.util :as mobile-util]
             [frontend.modules.outliner.op :as outliner-op]
             [frontend.modules.outliner.op :as outliner-op]
             [frontend.modules.outliner.ui :as ui-outliner-tx]
             [frontend.modules.outliner.ui :as ui-outliner-tx]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.util :as util]
             [frontend.util :as util]
             [frontend.util.file-based.clock :as clock]
             [frontend.util.file-based.clock :as clock]
             [frontend.util.file-based.drawer :as drawer]
             [frontend.util.file-based.drawer :as drawer]
-            [goog.crypt.base64 :as base64]
             [logseq.common.path :as path]
             [logseq.common.path :as path]
             [logseq.common.util :as common-util]
             [logseq.common.util :as common-util]
             [logseq.common.util.block-ref :as block-ref]
             [logseq.common.util.block-ref :as block-ref]
@@ -302,51 +299,28 @@
    (p/all
    (p/all
     (for [[index ^js file] (map-indexed vector files)]
     (for [[index ^js file] (map-indexed vector files)]
       ;; WARN file name maybe fully qualified path when paste file
       ;; WARN file name maybe fully qualified path when paste file
-      (p/let [file-name (util/node-path.basename (.-name file))
-              [file-stem ext-full ext-base] (if file-name
-                                              (let [ext-base (util/node-path.extname file-name)
-                                                    ext-full (if-not (config/extname-of-supported? ext-base)
-                                                               (util/full-path-extname file-name) ext-base)]
-                                                [(subs file-name 0 (- (count file-name)
-                                                                      (count ext-full))) ext-full ext-base])
-                                              ["" "" ""])
-              filename  (str (gen-filename index file-stem) ext-full)
-              file-rpath  (str asset-dir-rpath "/" filename)
-              matched-alias (assets-handler/get-matched-alias-by-ext ext-base)
-              file-rpath (cond-> file-rpath
-                           (not (nil? matched-alias))
-                           (string/replace #"^[.\/\\]*assets[\/\\]+" ""))
-              dir (or (:dir matched-alias) repo-dir)]
-        (if (util/electron?)
-          (do (js/console.debug "Debug: Copy Asset #" dir file-rpath)
-              (-> (if-let [from (not-empty (.-path file))]
-                    (js/window.apis.copyFileToAssets dir file-rpath from)
-                    (p/let [content (.arrayBuffer file)]
-                      (fs/write-file! repo repo-dir file-rpath content {:skip-compare? true})))
-                  (p/then
-                   (fn [dest]
-                     [file-rpath
-                      (if (string? dest) (js/File. #js[] dest) file)
-                      (path/path-join dir file-rpath)
-                      matched-alias]))
-                  (p/catch #(js/console.error "Debug: Copy Asset Error#" %))))
+      (let [file-name (util/node-path.basename (.-name file))
+            [file-stem ext-full ext-base] (if file-name
+                                            (let [ext-base (util/node-path.extname file-name)
+                                                  ext-full (if-not (config/extname-of-supported? ext-base)
+                                                             (util/full-path-extname file-name) ext-base)]
+                                              [(subs file-name 0 (- (count file-name)
+                                                                    (count ext-full))) ext-full ext-base])
+                                            ["" "" ""])
+            filename  (str (gen-filename index file-stem) ext-full)
+            file-rpath  (str asset-dir-rpath "/" filename)
+            matched-alias (assets-handler/get-matched-alias-by-ext ext-base)
+            file-rpath (cond-> file-rpath
+                         (not (nil? matched-alias))
+                         (string/replace #"^[.\/\\]*assets[\/\\]+" ""))
+            dir (or (:dir matched-alias) repo-dir)]
 
 
-          (->
-           (p/do! (js/console.debug "Debug: Writing Asset #" dir file-rpath)
-                  (cond
-                    (mobile-util/native-platform?)
-                   ;; capacitor fs accepts Blob, File implements Blob
-                    (p/let [buffer (.arrayBuffer file)
-                            content (base64/encodeByteArray (js/Uint8Array. buffer))
-                            fpath (path/path-join dir file-rpath)]
-                      (capacitor-fs/<write-file-with-base64 fpath content))
-
-                    :else                ; nfs
-                    (fs/write-file! repo dir file-rpath (.stream file) nil))
-                  [file-rpath file (path/path-join dir file-rpath) matched-alias])
-           (p/catch (fn [error]
-                      (prn :paste-file-error)
-                      (js/console.error error))))))))))
+        (p/do! (js/console.debug "Debug: Writing Asset #" dir file-rpath)
+               (p/let [content (.arrayBuffer file)
+                       file-fpath (path/path-join dir file-rpath)]
+                 ;; file based version support electron only
+                 (ipc/ipc "writeFile" repo file-fpath content))
+               [file-rpath file (path/path-join dir file-rpath) matched-alias]))))))
 
 
 ;; assets/journals_2021_02_03_1612350230540_0.png
 ;; assets/journals_2021_02_03_1612350230540_0.png
 (defn resolve-relative-path
 (defn resolve-relative-path

+ 6 - 6
src/main/frontend/handler/file_based/events.cljs

@@ -17,7 +17,7 @@
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.events :as events]
             [frontend.handler.events :as events]
             [frontend.handler.file-based.file :as file-handler]
             [frontend.handler.file-based.file :as file-handler]
-            [frontend.handler.file-based.nfs :as nfs-handler]
+            [frontend.handler.file-based.native-fs :as nfs-handler]
             [frontend.handler.file-sync :as file-sync-handler]
             [frontend.handler.file-sync :as file-sync-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
             [frontend.handler.page :as page-handler]
             [frontend.handler.page :as page-handler]
@@ -289,11 +289,11 @@
                                  (let [dir (config/get-repo-dir repo)]
                                  (let [dir (config/get-repo-dir repo)]
                                    (p/let [content (fs/read-file dir file)]
                                    (p/let [content (fs/read-file dir file)]
                                      (let [new-content (string/replace content (str id) (str (random-uuid)))]
                                      (let [new-content (string/replace content (str id) (str (random-uuid)))]
-                                       (p/let [_ (fs/write-file! repo
-                                                                 dir
-                                                                 file
-                                                                 new-content
-                                                                 {})]
+                                       (p/let [_ (fs/write-plain-text-file! repo
+                                                                            dir
+                                                                            file
+                                                                            new-content
+                                                                            {})]
                                          (reset! resolved? true))))))
                                          (reset! resolved? true))))))
                      :class "inline mx-1")
                      :class "inline mx-1")
           "it."]])]]))
           "it."]])]]))

+ 41 - 54
src/main/frontend/handler/file_based/file.cljs

@@ -1,28 +1,25 @@
 (ns frontend.handler.file-based.file
 (ns frontend.handler.file-based.file
   "Provides util handler fns for file graph files"
   "Provides util handler fns for file graph files"
   (:refer-clojure :exclude [load-file])
   (:refer-clojure :exclude [load-file])
-  (:require [frontend.config :as config]
+  (:require [electron.ipc :as ipc]
+            [frontend.config :as config]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.db.file-based.model :as file-model]
             [frontend.db.file-based.model :as file-model]
             [frontend.fs :as fs]
             [frontend.fs :as fs]
-            [frontend.fs.nfs :as nfs]
-            [frontend.fs.capacitor-fs :as capacitor-fs]
-            [frontend.handler.file-based.reset-file :as reset-file-handler]
             [frontend.handler.common.config-edn :as config-edn-common-handler]
             [frontend.handler.common.config-edn :as config-edn-common-handler]
-            [frontend.handler.repo-config :as repo-config-handler]
+            [frontend.handler.file-based.reset-file :as reset-file-handler]
             [frontend.handler.global-config :as global-config-handler]
             [frontend.handler.global-config :as global-config-handler]
+            [frontend.handler.repo-config :as repo-config-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.schema.handler.global-config :as global-config-schema]
             [frontend.schema.handler.global-config :as global-config-schema]
             [frontend.schema.handler.repo-config :as repo-config-schema]
             [frontend.schema.handler.repo-config :as repo-config-schema]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.util :as util]
             [frontend.util :as util]
-            [logseq.common.util :as common-util]
-            [electron.ipc :as ipc]
             [lambdaisland.glogi :as log]
             [lambdaisland.glogi :as log]
-            [promesa.core :as p]
-            [frontend.mobile.util :as mobile-util]
+            [logseq.common.config :as common-config]
             [logseq.common.path :as path]
             [logseq.common.path :as path]
-            [logseq.common.config :as common-config]))
+            [logseq.common.util :as common-util]
+            [promesa.core :as p]))
 
 
 ;; TODO: extract all git ops using a channel
 ;; TODO: extract all git ops using a channel
 
 
@@ -32,9 +29,9 @@
    (p/let [content (fs/read-file (config/get-repo-dir repo-url) path)]
    (p/let [content (fs/read-file (config/get-repo-dir repo-url) path)]
      content)
      content)
    (p/catch
    (p/catch
-       (fn [e]
-         (println "Load file failed: " path)
-         (js/console.error e)))))
+    (fn [e]
+      (println "Load file failed: " path)
+      (js/console.error e)))))
 
 
 (defn- load-multiple-files
 (defn- load-multiple-files
   [repo-url paths]
   [repo-url paths]
@@ -64,7 +61,7 @@
     (-> (p/all (load-multiple-files repo-url files))
     (-> (p/all (load-multiple-files repo-url files))
         (p/then (fn [contents]
         (p/then (fn [contents]
                   (let [file-contents (cond->
                   (let [file-contents (cond->
-                                        (zipmap files contents)
+                                       (zipmap files contents)
 
 
                                         (seq images)
                                         (seq images)
                                         (merge (zipmap images (repeat (count images) ""))))
                                         (merge (zipmap images (repeat (count images) ""))))
@@ -73,21 +70,14 @@
                                          :file/content content})]
                                          :file/content content})]
                     (ok-handler file-contents))))
                     (ok-handler file-contents))))
         (p/catch (fn [error]
         (p/catch (fn [error]
-                   (log/error :nfs/load-files-error repo-url)
+                   (log/error :fs/load-files-error repo-url)
                    (log/error :exception error))))))
                    (log/error :exception error))))))
 
 
 (defn backup-file!
 (defn backup-file!
   "Backup db content to bak directory"
   "Backup db content to bak directory"
   [repo-url path db-content content]
   [repo-url path db-content content]
-  (cond
-    (util/electron?)
-    (ipc/ipc "backupDbFile" repo-url path db-content content)
-
-    (mobile-util/native-platform?)
-    (capacitor-fs/backup-file-handle-changed! repo-url path db-content)
-
-    :else
-    nil))
+  (when (util/electron?)
+    (ipc/ipc "backupDbFile" repo-url path db-content content)))
 
 
 (defn- detect-deprecations
 (defn- detect-deprecations
   [path content]
   [path content]
@@ -115,7 +105,7 @@
         path-dir (config/get-repo-dir repo)
         path-dir (config/get-repo-dir repo)
         write-file-options' (merge write-file-options
         write-file-options' (merge write-file-options
                                    (when original-content {:old-content original-content}))]
                                    (when original-content {:old-content original-content}))]
-    (fs/write-file! repo path-dir path content write-file-options')))
+    (fs/write-plain-text-file! repo path-dir path content write-file-options')))
 
 
 (defn alter-global-file
 (defn alter-global-file
   "Does pre-checks on a global file, writes if it's not already written
   "Does pre-checks on a global file, writes if it's not already written
@@ -126,18 +116,18 @@
     (do
     (do
       (detect-deprecations path content)
       (detect-deprecations path content)
       (when (validate-file path content)
       (when (validate-file path content)
-       (-> (p/let [_ (when-not from-disk?
-                       (fs/write-file! "" nil path content {:skip-compare? true}))]
-                  (p/do! (global-config-handler/restore-global-config!)
-                         (state/pub-event! [:shortcut/refresh])))
-           (p/catch (fn [error]
-                      (state/pub-event! [:notification/show
-                                         {:content (str "Failed to write to file " path ", error: " error)
-                                          :status :error}])
-                      (log/error :write/failed error)
-                      (state/pub-event! [:capture-error
-                                         {:error error
-                                          :payload {:type :write-file/failed-for-alter-file}}]))))))
+        (-> (p/let [_ (when-not from-disk?
+                        (fs/write-plain-text-file! "" nil path content {:skip-compare? true}))]
+              (p/do! (global-config-handler/restore-global-config!)
+                     (state/pub-event! [:shortcut/refresh])))
+            (p/catch (fn [error]
+                       (state/pub-event! [:notification/show
+                                          {:content (str "Failed to write to file " path ", error: " error)
+                                           :status :error}])
+                       (log/error :write/failed error)
+                       (state/pub-event! [:capture-error
+                                          {:error error
+                                           :payload {:type :write-file/failed-for-alter-file}}]))))))
     (log/error :msg "alter-global-file does not support this file" :file path)))
     (log/error :msg "alter-global-file does not support this file" :file path)))
 
 
 (defn alter-file
 (defn alter-file
@@ -209,23 +199,20 @@
                        (when path
                        (when path
                          (let [path (common-util/path-normalize path)
                          (let [path (common-util/path-normalize path)
                                original-content (get file->content path)]
                                original-content (get file->content path)]
-                          (-> (p/let [_ (or
-                                         (util/electron?)
-                                         (nfs/check-directory-permission! repo))]
-                                (fs/write-file! repo (config/get-repo-dir repo) path content
-                                                {:old-content original-content}))
-                              (p/catch (fn [error]
-                                         (state/pub-event! [:notification/show
-                                                            {:content (str "Failed to save the file " path ". Error: "
-                                                                           (str error))
-                                                             :status :error
-                                                             :clear? false}])
-                                         (state/pub-event! [:capture-error
-                                                            {:error error
-                                                             :payload {:type :write-file/failed}}])
-                                         (log/error :write-file/failed {:path path
-                                                                        :content content
-                                                                        :error error})))))))
+                           (-> (fs/write-plain-text-file! repo (config/get-repo-dir repo) path content
+                                                          {:old-content original-content})
+                               (p/catch (fn [error]
+                                          (state/pub-event! [:notification/show
+                                                             {:content (str "Failed to save the file " path ". Error: "
+                                                                            (str error))
+                                                              :status :error
+                                                              :clear? false}])
+                                          (state/pub-event! [:capture-error
+                                                             {:error error
+                                                              :payload {:type :write-file/failed}}])
+                                          (log/error :write-file/failed {:path path
+                                                                         :content content
+                                                                         :error error})))))))
         finish-handler (fn []
         finish-handler (fn []
                          (when finish-handler
                          (when finish-handler
                            (finish-handler)))]
                            (finish-handler)))]

+ 5 - 7
src/main/frontend/handler/file_based/nfs.cljs → src/main/frontend/handler/file_based/native_fs.cljs

@@ -1,12 +1,11 @@
-(ns frontend.handler.file-based.nfs
-  "The File System Access API, https://web.dev/file-system-access/."
+(ns frontend.handler.file-based.native-fs
+  "Native fs including Electron and mobile"
   (:require ["/frontend/utils" :as utils]
   (:require ["/frontend/utils" :as utils]
             [clojure.set :as set]
             [clojure.set :as set]
             [clojure.string :as string]
             [clojure.string :as string]
             [frontend.config :as config]
             [frontend.config :as config]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.fs :as fs]
             [frontend.fs :as fs]
-            [frontend.fs.nfs :as nfs]
             [frontend.handler.common :as common-handler]
             [frontend.handler.common :as common-handler]
             [frontend.handler.file-based.repo :as file-repo-handler]
             [frontend.handler.file-based.repo :as file-repo-handler]
             [frontend.handler.global-config :as global-config-handler]
             [frontend.handler.global-config :as global-config-handler]
@@ -142,7 +141,7 @@
                                      (state/set-loading-files! repo false)
                                      (state/set-loading-files! repo false)
                                      (when ok-handler (ok-handler {:url repo})))))))
                                      (when ok-handler (ok-handler {:url repo})))))))
                 (p/catch (fn [error]
                 (p/catch (fn [error]
-                           (log/error :nfs/load-files-error repo)
+                           (log/error :fs/load-files-error repo)
                            (log/error :exception error)))))))
                            (log/error :exception error)))))))
       (p/catch (fn [error]
       (p/catch (fn [error]
                  (log/error :exception error)
                  (log/error :exception error)
@@ -253,8 +252,7 @@
       (->
       (->
        (p/let [handle (when-not electron? (idb/get-item handle-path))]
        (p/let [handle (when-not electron? (idb/get-item handle-path))]
          (when (or handle electron? mobile-native?)
          (when (or handle electron? mobile-native?)
-           (p/let [_ (when nfs? (nfs/verify-permission repo true))
-                   local-files-result (fs/get-files repo-dir)
+           (p/let [local-files-result (fs/get-files repo-dir)
                    _ (when (config/global-config-enabled?)
                    _ (when (config/global-config-enabled?)
                        ;; reload global config into state
                        ;; reload global config into state
                        (global-config-handler/restore-global-config!))
                        (global-config-handler/restore-global-config!))
@@ -262,7 +260,7 @@
                                  (remove-ignore-files repo-dir nfs?))]
                                  (remove-ignore-files repo-dir nfs?))]
              (handle-diffs! repo nfs? old-files new-files re-index? ok-handler))))
              (handle-diffs! repo nfs? old-files new-files re-index? ok-handler))))
        (p/catch (fn [error]
        (p/catch (fn [error]
-                  (log/error :nfs/load-files-error repo)
+                  (log/error :fs/load-files-error repo)
                   (log/error :exception error)))
                   (log/error :exception error)))
        (p/finally (fn [_]
        (p/finally (fn [_]
                     (state/set-graph-syncing? false)))))))
                     (state/set-graph-syncing? false)))))))

+ 15 - 51
src/main/frontend/handler/file_based/repo.cljs

@@ -1,25 +1,25 @@
 (ns frontend.handler.file-based.repo
 (ns frontend.handler.file-based.repo
   "Repo fns for creating, loading and parsing file graphs"
   "Repo fns for creating, loading and parsing file graphs"
-  (:require [frontend.config :as config]
+  (:require [clojure.core.async :as async]
+            [clojure.core.async.interop :refer [p->c]]
+            [frontend.config :as config]
             [frontend.db :as db]
             [frontend.db :as db]
             [frontend.db.file-based.model :as file-model]
             [frontend.db.file-based.model :as file-model]
             [frontend.fs :as fs]
             [frontend.fs :as fs]
             [frontend.handler.file-based.file :as file-handler]
             [frontend.handler.file-based.file :as file-handler]
-            [frontend.handler.repo-config :as repo-config-handler]
             [frontend.handler.file-based.reset-file :as reset-file-handler]
             [frontend.handler.file-based.reset-file :as reset-file-handler]
+            [frontend.handler.repo-config :as repo-config-handler]
             [frontend.handler.route :as route-handler]
             [frontend.handler.route :as route-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.spec :as spec]
             [frontend.spec :as spec]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.util :as util]
             [frontend.util :as util]
-            [promesa.core :as p]
-            [shadow.resource :as rc]
-            [logseq.graph-parser :as graph-parser]
             [logseq.common.config :as common-config]
             [logseq.common.config :as common-config]
-            [clojure.core.async :as async]
-            [medley.core :as medley]
             [logseq.common.path :as path]
             [logseq.common.path :as path]
-            [clojure.core.async.interop :refer [p->c]]))
+            [logseq.graph-parser :as graph-parser]
+            [medley.core :as medley]
+            [promesa.core :as p]
+            [shadow.resource :as rc]))
 
 
 (defn- create-contents-file
 (defn- create-contents-file
   [repo-url]
   [repo-url]
@@ -54,49 +54,13 @@
 
 
 (comment
 (comment
   (defn- create-dummy-notes-page
   (defn- create-dummy-notes-page
-   [repo-url content]
-   (spec/validate :repos/url repo-url)
-   (let [repo-dir (config/get-repo-dir repo-url)
-         file-rpath (str (config/get-pages-directory) "/how_to_make_dummy_notes.md")]
-     (p/let [_ (fs/mkdir-if-not-exists (path/path-join repo-dir (config/get-pages-directory)))
-             _file-exists? (fs/create-if-not-exists repo-url repo-dir file-rpath content)]
-       (reset-file-handler/reset-file! repo-url file-rpath content)))))
-
-(comment
-  (defn- create-today-journal-if-not-exists
-   [repo-url {:keys [content]}]
-   (spec/validate :repos/url repo-url)
-   (when (state/enable-journals? repo-url)
-     (let [repo-dir (config/get-repo-dir repo-url)
-           format (state/get-preferred-format repo-url)
-           title (date/today)
-           file-name (date/journal-title->default title)
-           default-content (util/default-content-with-title format)
-           template (state/get-default-journal-template)
-           template (when (and template
-                               (not (string/blank? template)))
-                      template)
-           content (cond
-                     content
-                     content
-
-                     template
-                     (str default-content template)
-
-                     :else
-                     default-content)
-           file-rpath (path/path-join (config/get-journals-directory) (str file-name "."
-                                                                           (config/get-file-extension format)))
-           page-exists? (ldb/get-page (db/get-db) title)
-           empty-blocks? (db/page-empty? repo-url (util/page-name-sanity-lc title))]
-       (when (or empty-blocks? (not page-exists?))
-         (p/let [_ (nfs/check-directory-permission! repo-url)
-                 _ (fs/mkdir-if-not-exists (path/path-join repo-dir (config/get-journals-directory)))
-                 file-exists? (fs/file-exists? repo-dir file-rpath)]
-           (when-not file-exists?
-             (p/let [_ (reset-file-handler/reset-file! repo-url file-rpath content)]
-               (fs/create-if-not-exists repo-url repo-dir file-rpath content)))))))))
-
+    [repo-url content]
+    (spec/validate :repos/url repo-url)
+    (let [repo-dir (config/get-repo-dir repo-url)
+          file-rpath (str (config/get-pages-directory) "/how_to_make_dummy_notes.md")]
+      (p/let [_ (fs/mkdir-if-not-exists (path/path-join repo-dir (config/get-pages-directory)))
+              _file-exists? (fs/create-if-not-exists repo-url repo-dir file-rpath content)]
+        (reset-file-handler/reset-file! repo-url file-rpath content)))))
 
 
 (defn create-config-file-if-not-exists
 (defn create-config-file-if-not-exists
   "Creates a default logseq/config.edn if it doesn't exist"
   "Creates a default logseq/config.edn if it doesn't exist"

+ 13 - 13
src/main/frontend/handler/global_config.cljs

@@ -2,14 +2,14 @@
   "This ns is a system component that encapsulates global config functionality.
   "This ns is a system component that encapsulates global config functionality.
   Unlike repo config, this also manages a directory for configuration. This
   Unlike repo config, this also manages a directory for configuration. This
   component depends on a repo."
   component depends on a repo."
-  (:require [frontend.fs :as fs]
-            [frontend.state :as state]
-            [promesa.core :as p]
-            [shadow.resource :as rc]
+  (:require [borkdude.rewrite-edn :as rewrite]
             [clojure.edn :as edn]
             [clojure.edn :as edn]
             [electron.ipc :as ipc]
             [electron.ipc :as ipc]
-            [borkdude.rewrite-edn :as rewrite]
-            [logseq.common.path :as path]))
+            [frontend.fs :as fs]
+            [frontend.state :as state]
+            [logseq.common.path :as path]
+            [promesa.core :as p]
+            [shadow.resource :as rc]))
 
 
 ;; Use defonce to avoid broken state on dev reload
 ;; Use defonce to avoid broken state on dev reload
 ;; Also known as home directory a.k.a. '~'
 ;; Also known as home directory a.k.a. '~'
@@ -50,30 +50,30 @@
         config-path (global-config-path)]
         config-path (global-config-path)]
     (p/let [_ (fs/mkdir-if-not-exists config-dir)
     (p/let [_ (fs/mkdir-if-not-exists config-dir)
             file-exists? (fs/create-if-not-exists repo-url nil config-path default-content)]
             file-exists? (fs/create-if-not-exists repo-url nil config-path default-content)]
-           (when-not file-exists?
-             (set-global-config-state! default-content)))))
+      (when-not file-exists?
+        (set-global-config-state! default-content)))))
 
 
 (defn restore-global-config!
 (defn restore-global-config!
   "Sets global config state from config file"
   "Sets global config state from config file"
   []
   []
   (let [config-path (global-config-path)]
   (let [config-path (global-config-path)]
     (p/let [config-content (fs/read-file nil config-path)]
     (p/let [config-content (fs/read-file nil config-path)]
-           (set-global-config-state! config-content))))
+      (set-global-config-state! config-content))))
 
 
 (defn set-global-config-kv!
 (defn set-global-config-kv!
   [k v]
   [k v]
   (let [result (rewrite/parse-string
   (let [result (rewrite/parse-string
-                 (or (state/get-global-config-str-content) "{}"))
+                (or (state/get-global-config-str-content) "{}"))
         ks (if (sequential? k) k [k])
         ks (if (sequential? k) k [k])
         v (cond->> v
         v (cond->> v
-                   (map? v)
-                   (reduce-kv (fn [a k v] (rewrite/assoc a k v)) (rewrite/parse-string "{}")))
+            (map? v)
+            (reduce-kv (fn [a k v] (rewrite/assoc a k v)) (rewrite/parse-string "{}")))
         new-result (if (and (= 1 (count ks))
         new-result (if (and (= 1 (count ks))
                             (nil? v))
                             (nil? v))
                      (rewrite/dissoc result (first ks))
                      (rewrite/dissoc result (first ks))
                      (rewrite/assoc-in result ks v))
                      (rewrite/assoc-in result ks v))
         new-str-content (str new-result)]
         new-str-content (str new-result)]
-    (fs/write-file! nil nil (global-config-path) new-str-content {:skip-compare? true})
+    (fs/write-plain-text-file! nil nil (global-config-path) new-str-content {:skip-compare? true})
     (state/set-global-config! (rewrite/sexpr new-result) new-str-content)))
     (state/set-global-config! (rewrite/sexpr new-result) new-str-content)))
 
 
 (defn start
 (defn start

+ 2 - 2
src/main/frontend/handler/page.cljs

@@ -17,7 +17,7 @@
             [frontend.handler.db-based.page :as db-page-handler]
             [frontend.handler.db-based.page :as db-page-handler]
             [frontend.handler.db-based.property :as db-property-handler]
             [frontend.handler.db-based.property :as db-property-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.editor :as editor-handler]
-            [frontend.handler.file-based.nfs :as nfs-handler]
+            [frontend.handler.file-based.native-fs :as nfs-handler]
             [frontend.handler.file-based.page :as file-page-handler]
             [frontend.handler.file-based.page :as file-page-handler]
             [frontend.handler.file-based.page-property :as file-page-property]
             [frontend.handler.file-based.page-property :as file-page-property]
             [frontend.handler.graph :as graph-handler]
             [frontend.handler.graph :as graph-handler]
@@ -28,7 +28,7 @@
             [frontend.mobile.util :as mobile-util]
             [frontend.mobile.util :as mobile-util]
             [frontend.modules.outliner.op :as outliner-op]
             [frontend.modules.outliner.op :as outliner-op]
             [frontend.modules.outliner.ui :as ui-outliner-tx]
             [frontend.modules.outliner.ui :as ui-outliner-tx]
-            [frontend.ref :as ref]
+            [frontend.util.ref :as ref]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.util :as util]
             [frontend.util :as util]
             [frontend.util.cursor :as cursor]
             [frontend.util.cursor :as cursor]

+ 23 - 16
src/main/frontend/handler/plugin.cljs

@@ -67,6 +67,13 @@
   (invoke-exported-api :unlink_installed_web_plugin key)
   (invoke-exported-api :unlink_installed_web_plugin key)
   (invoke-exported-api :unlink_plugin_user_settings key))
   (invoke-exported-api :unlink_plugin_user_settings key))
 
 
+(defn assets-theme-to-file
+  [theme]
+  (when theme
+    (cond-> theme
+      (util/electron?)
+      (update :url #(some-> % (string/replace-first "assets://" "file://"))))))
+
 (defn load-plugin-preferences
 (defn load-plugin-preferences
   []
   []
   (-> (invoke-exported-api :load_user_preferences)
   (-> (invoke-exported-api :load_user_preferences)
@@ -211,7 +218,6 @@
                    (let [e (or evt ctx)]
                    (let [e (or evt ctx)]
                      (when-let [{:keys [status payload only-check]} (bean/->clj e)]
                      (when-let [{:keys [status payload only-check]} (bean/->clj e)]
                        (case (keyword status)
                        (case (keyword status)
-
                          :completed
                          :completed
                          (let [{:keys [id dst name title theme web-pkg]} payload
                          (let [{:keys [id dst name title theme web-pkg]} payload
                                name (or title name "Untitled")]
                                name (or title name "Untitled")]
@@ -333,6 +339,7 @@
                      :action (fn []
                      :action (fn []
                                (state/pub-event!
                                (state/pub-event!
                                 [:exec-plugin-cmd {:type type :key key :pid pid :cmd cmd :action action}]))}]
                                 [:exec-plugin-cmd {:type type :key key :pid pid :cmd cmd :action action}]))}]
+
     palette-cmd))
     palette-cmd))
 
 
 (defn simple-cmd-keybinding->shortcut-args
 (defn simple-cmd-keybinding->shortcut-args
@@ -483,7 +490,7 @@
 (defn select-a-plugin-theme
 (defn select-a-plugin-theme
   [pid]
   [pid]
   (when-let [themes (get (group-by :pid (:plugin/installed-themes @state/state)) pid)]
   (when-let [themes (get (group-by :pid (:plugin/installed-themes @state/state)) pid)]
-    (when-let [theme (first themes)]
+    (when-let [theme (assets-theme-to-file (first themes))]
       (js/LSPluginCore.selectTheme (bean/->js theme)))))
       (js/LSPluginCore.selectTheme (bean/->js theme)))))
 
 
 (defn update-plugin-settings-state
 (defn update-plugin-settings-state
@@ -642,7 +649,7 @@
             dotroot (get-ls-dotdir-root)
             dotroot (get-ls-dotdir-root)
             filepath (util/node-path.join dotroot dirname (str key ".json"))]
             filepath (util/node-path.join dotroot dirname (str key ".json"))]
         (if (util/electron?)
         (if (util/electron?)
-          (fs/write-file! repo nil filepath (js/JSON.stringify data nil 2) {:skip-compare? true})
+          (fs/write-plain-text-file! repo nil filepath (js/JSON.stringify data nil 2) {:skip-compare? true})
           (idb/set-item! filepath data))))))
           (idb/set-item! filepath data))))))
 
 
 (defn make-fn-to-unlink-dotdir-json
 (defn make-fn-to-unlink-dotdir-json
@@ -884,13 +891,13 @@
 
 
                   (.on "themes-changed" (fn [^js themes]
                   (.on "themes-changed" (fn [^js themes]
                                           (swap! state/state assoc :plugin/installed-themes
                                           (swap! state/state assoc :plugin/installed-themes
-                                                 (vec (mapcat (fn [[pid vs]] (mapv #(assoc % :pid pid) (bean/->clj vs))) (bean/->clj themes))))))
+                                            (vec (mapcat (fn [[pid vs]] (mapv #(assoc % :pid pid) (bean/->clj vs))) (bean/->clj themes))))))
 
 
-                  (.on "theme-selected" (fn [^js theme ^js opts]
+                  (.on "theme-selected" (fn [^js theme]
                                           (let [theme (bean/->clj theme)
                                           (let [theme (bean/->clj theme)
-                                                _opts (bean/->clj opts)
-                                                url (:url theme)
-                                                mode (or (:mode theme) (state/sub :ui/theme))]
+                                                theme (assets-theme-to-file theme)
+                                                url   (:url theme)
+                                                mode  (or (:mode theme) (state/sub :ui/theme))]
                                             (when mode
                                             (when mode
                                               (state/set-custom-theme! mode theme)
                                               (state/set-custom-theme! mode theme)
                                               (state/set-theme-mode! mode))
                                               (state/set-theme-mode! mode))
@@ -939,16 +946,16 @@
         plugins-async)
         plugins-async)
 
 
       (p/then
       (p/then
-        (fn [plugins-async]
+       (fn [plugins-async]
           ;; true indicate for preboot finished
           ;; true indicate for preboot finished
-          (state/set-state! :plugin/indicator-text true)
+         (state/set-state! :plugin/indicator-text true)
           ;; wait for the plugin register async messages
           ;; wait for the plugin register async messages
-          (js/setTimeout
-            (fn [] (callback)
-              (some-> (seq plugins-async)
-                (p/delay 16)
-                (p/then #(.register js/LSPluginCore (bean/->js plugins-async) true))))
-            (if (util/electron?) 64 0))))
+         (js/setTimeout
+          (fn [] (callback)
+            (some-> (seq plugins-async)
+                    (p/delay 16)
+                    (p/then #(.register js/LSPluginCore (bean/->js plugins-async) true))))
+          (if (util/electron?) 64 0))))
       (p/catch
       (p/catch
        (fn [^js e]
        (fn [^js e]
          (log/error :setup-plugin-system-error e)
          (log/error :setup-plugin-system-error e)

+ 2 - 2
src/main/frontend/handler/plugin_config.cljs

@@ -40,14 +40,14 @@ when a plugin is installed, updated or removed"
                               str)]
                               str)]
          ;; fs protocols require repo and dir when they aren't necessary. For this component,
          ;; fs protocols require repo and dir when they aren't necessary. For this component,
          ;; neither is needed so these are blank and nil respectively
          ;; neither is needed so these are blank and nil respectively
-    (fs/write-file! "" nil (plugin-config-path) updated-content {:skip-compare? true})))
+    (fs/write-plain-text-file! "" nil (plugin-config-path) updated-content {:skip-compare? true})))
 
 
 (defn remove-plugin
 (defn remove-plugin
   "Removes a plugin from plugin.edn"
   "Removes a plugin from plugin.edn"
   [plugin-id]
   [plugin-id]
   (p/let [content (fs/read-file "" (plugin-config-path))
   (p/let [content (fs/read-file "" (plugin-config-path))
           updated-content (-> content rewrite/parse-string (rewrite/dissoc (keyword plugin-id)) str)]
           updated-content (-> content rewrite/parse-string (rewrite/dissoc (keyword plugin-id)) str)]
-    (fs/write-file! "" nil (plugin-config-path) updated-content {:skip-compare? true})))
+    (fs/write-plain-text-file! "" nil (plugin-config-path) updated-content {:skip-compare? true})))
 
 
 (defn- create-plugin-config-file-if-not-exists
 (defn- create-plugin-config-file-if-not-exists
   []
   []

+ 6 - 3
src/main/frontend/handler/user.cljs

@@ -127,12 +127,16 @@
   ([id-token access-token]
   ([id-token access-token]
    (state/set-auth-id-token id-token)
    (state/set-auth-id-token id-token)
    (state/set-auth-access-token access-token)
    (state/set-auth-access-token access-token)
-   (set-token-to-localstorage! id-token access-token))
+   (set-token-to-localstorage! id-token access-token)
+   (some->> (parse-jwt (state/get-auth-id-token))
+            (reset! flows/*current-login-user)))
   ([id-token access-token refresh-token]
   ([id-token access-token refresh-token]
    (state/set-auth-id-token id-token)
    (state/set-auth-id-token id-token)
    (state/set-auth-access-token access-token)
    (state/set-auth-access-token access-token)
    (state/set-auth-refresh-token refresh-token)
    (state/set-auth-refresh-token refresh-token)
-   (set-token-to-localstorage! id-token access-token refresh-token)))
+   (set-token-to-localstorage! id-token access-token refresh-token)
+   (some->> (parse-jwt (state/get-auth-id-token))
+            (reset! flows/*current-login-user))))
 
 
 (defn- <refresh-tokens
 (defn- <refresh-tokens
   "return refreshed id-token, access-token"
   "return refreshed id-token, access-token"
@@ -201,7 +205,6 @@
    (:jwtToken (:idToken session))
    (:jwtToken (:idToken session))
    (:jwtToken (:accessToken session))
    (:jwtToken (:accessToken session))
    (:token (:refreshToken session)))
    (:token (:refreshToken session)))
-  (reset! flows/*current-login-user (parse-jwt (state/get-auth-id-token)))
   (state/pub-event! [:user/fetch-info-and-graphs]))
   (state/pub-event! [:user/fetch-info-and-graphs]))
 
 
 (defn ^:export login-with-username-password-e2e
 (defn ^:export login-with-username-password-e2e

+ 8 - 7
src/main/frontend/idb.cljs

@@ -21,13 +21,14 @@
   (when (and key @store)
   (when (and key @store)
     (idb-keyval/set key value @store)))
     (idb-keyval/set key value @store)))
 
 
-(defn rename-item!
-  [old-key new-key]
-  (when (and old-key new-key @store)
-    (p/let [value (idb-keyval/get old-key @store)]
-      (when value
-        (idb-keyval/set new-key value @store)
-        (idb-keyval/del old-key @store)))))
+(comment
+  (defn rename-item!
+    [old-key new-key]
+    (when (and old-key new-key @store)
+      (p/let [value (idb-keyval/get old-key @store)]
+        (when value
+          (idb-keyval/set new-key value @store)
+          (idb-keyval/del old-key @store))))))
 
 
 (comment
 (comment
   (defn set-batch!
   (defn set-batch!

+ 1 - 1
src/main/frontend/mobile/action_bar.cljs

@@ -7,7 +7,7 @@
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.mixins :as mixins]
             [frontend.mixins :as mixins]
             [frontend.mobile.util :as mobile-util]
             [frontend.mobile.util :as mobile-util]
-            [frontend.ref :as ref]
+            [frontend.util.ref :as ref]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.ui :as ui]
             [frontend.util :as util]
             [frontend.util :as util]

+ 4 - 51
src/main/frontend/mobile/core.cljs

@@ -3,16 +3,12 @@
   (:require ["@capacitor/app" :refer [^js App]]
   (:require ["@capacitor/app" :refer [^js App]]
             ["@capacitor/keyboard" :refer [^js Keyboard]]
             ["@capacitor/keyboard" :refer [^js Keyboard]]
             [clojure.string :as string]
             [clojure.string :as string]
-            [promesa.core :as p]
-            [frontend.fs.capacitor-fs :as capacitor-fs]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.mobile.deeplink :as deeplink]
             [frontend.mobile.deeplink :as deeplink]
             [frontend.mobile.intent :as intent]
             [frontend.mobile.intent :as intent]
             [frontend.mobile.util :as mobile-util]
             [frontend.mobile.util :as mobile-util]
             [frontend.state :as state]
             [frontend.state :as state]
-            [frontend.util :as util]
-            [cljs-bean.core :as bean]
-            [frontend.config :as config]))
+            [frontend.util :as util]))
 
 
 (def *init-url (atom nil))
 (def *init-url (atom nil))
 ;; FIXME: `appUrlOpen` are fired twice when receiving a same intent.
 ;; FIXME: `appUrlOpen` are fired twice when receiving a same intent.
@@ -21,14 +17,6 @@
 (def *last-shared-url (atom nil))
 (def *last-shared-url (atom nil))
 (def *last-shared-seconds (atom 0))
 (def *last-shared-seconds (atom 0))
 
 
-(defn mobile-preinit
-  "preinit logic of mobile platforms: setup document folder permission"
-  []
-  (when (mobile-util/native-ios?)
-    ;; Caution: This must be called before any file accessing
-    (capacitor-fs/ios-ensure-documents!)))
-
-
 (defn mobile-postinit
 (defn mobile-postinit
   "postinit logic of mobile platforms: handle deeplink and intent"
   "postinit logic of mobile platforms: handle deeplink and intent"
   []
   []
@@ -40,30 +28,7 @@
 (defn- ios-init
 (defn- ios-init
   "Initialize iOS-specified event listeners"
   "Initialize iOS-specified event listeners"
   []
   []
-  (p/let [^js paths (capacitor-fs/ios-ensure-documents!)]
-    (when paths
-      (let [paths (-> paths
-                      bean/->clj
-                      (update-vals capacitor-fs/ios-force-include-private))]
-        (state/set-state! :mobile/container-urls paths)
-        (println "iOS container path: " paths))))
-
-  ;; Fix iOS App directory change across installation
-  (when (not (config/demo-graph?))
-    (state/pub-event! [:validate-appId]))
-
-  (mobile-util/check-ios-zoomed-display)
-
-  ;; keep this the same logic as src/main/electron/listener.cljs
-  (.addListener mobile-util/file-sync "debug"
-                (fn [event]
-                  (let [event (js->clj event :keywordize-keys true)
-                        payload (:data event)]
-                    (when (or (= (:event event) "download:progress")
-                              (= (:event event) "upload:progress"))
-                      (state/set-state! [:file-sync/graph-state (:graphUUID payload) :file-sync/progress (:file payload)] payload))))))
-
-
+  (mobile-util/check-ios-zoomed-display))
 
 
 (defn- android-init
 (defn- android-init
   "Initialize Android-specified event listeners"
   "Initialize Android-specified event listeners"
@@ -98,13 +63,7 @@
                        (js/window.history.back)))))
                        (js/window.history.back)))))
 
 
   (.addEventListener js/window "sendIntentReceived"
   (.addEventListener js/window "sendIntentReceived"
-                     #(intent/handle-received))
-
-  (.addListener mobile-util/file-sync "progress"
-                (fn [event]
-                  (js/console.log "🔄" event)
-                  (let [event (js->clj event :keywordize-keys true)]
-                    (state/set-state! [:file-sync/graph-state (:graphUUID event) :file-sync/progress (:file event)] event)))))
+                     #(intent/handle-received)))
 
 
 (defn- app-state-change-handler
 (defn- app-state-change-handler
   [^js state]
   [^js state]
@@ -112,8 +71,7 @@
   (when (state/get-current-repo)
   (when (state/get-current-repo)
     (let [is-active? (.-isActive state)]
     (let [is-active? (.-isActive state)]
       (when-not is-active?
       (when-not is-active?
-        (editor-handler/save-current-block!))
-      (state/set-mobile-app-state-change is-active?))))
+        (editor-handler/save-current-block!)))))
 
 
 (defn- general-init
 (defn- general-init
   "Initialize event listeners used by both iOS and Android"
   "Initialize event listeners used by both iOS and Android"
@@ -129,10 +87,6 @@
                         (reset! *last-shared-seconds (.getSeconds (js/Date.)))
                         (reset! *last-shared-seconds (.getSeconds (js/Date.)))
                         (deeplink/deeplink url))))))
                         (deeplink/deeplink url))))))
 
 
-  (.addListener mobile-util/fs-watcher "watcher"
-                (fn [event]
-                  (state/pub-event! [:mobile-file-watcher/changed event])))
-
   (.addListener Keyboard "keyboardWillShow"
   (.addListener Keyboard "keyboardWillShow"
                 (fn [^js info]
                 (fn [^js info]
                   (let [keyboard-height (.-keyboardHeight info)]
                   (let [keyboard-height (.-keyboardHeight info)]
@@ -147,7 +101,6 @@
 
 
   (.addListener App "appStateChange" app-state-change-handler))
   (.addListener App "appStateChange" app-state-change-handler))
 
 
-
 (defn init! []
 (defn init! []
   (when (mobile-util/native-android?)
   (when (mobile-util/native-android?)
     (android-init))
     (android-init))

+ 1 - 1
src/main/frontend/mobile/graph_picker.cljs

@@ -3,7 +3,7 @@
    [clojure.string :as string]
    [clojure.string :as string]
    [frontend.components.svg :as svg]
    [frontend.components.svg :as svg]
    [frontend.fs :as fs]
    [frontend.fs :as fs]
-   [frontend.handler.file-based.nfs :as nfs-handler]
+   [frontend.handler.file-based.native-fs :as nfs-handler]
    [frontend.handler.notification :as notification]
    [frontend.handler.notification :as notification]
    [frontend.handler.page :as page-handler]
    [frontend.handler.page :as page-handler]
    [frontend.mobile.util :as mobile-util]
    [frontend.mobile.util :as mobile-util]

+ 1 - 1
src/main/frontend/mobile/intent.cljs

@@ -14,7 +14,7 @@
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
             [frontend.mobile.util :as mobile-util]
             [frontend.mobile.util :as mobile-util]
-            [frontend.ref :as ref]
+            [frontend.util.ref :as ref]
             [frontend.state :as state]
             [frontend.state :as state]
             [frontend.util :as util]
             [frontend.util :as util]
             [frontend.util.fs :as fs-util]
             [frontend.util.fs :as fs-util]

+ 10 - 22
src/main/frontend/mobile/util.cljs

@@ -1,10 +1,8 @@
 (ns frontend.mobile.util
 (ns frontend.mobile.util
-  (:require ["@capacitor/core" :refer [Capacitor registerPlugin ^js Plugins]]
+  (:require ["@capacitor/core" :refer [Capacitor registerPlugin]]
             ["@capacitor/splash-screen" :refer [SplashScreen]]
             ["@capacitor/splash-screen" :refer [SplashScreen]]
-            ["@logseq/capacitor-file-sync" :refer [FileSync]]
             [clojure.string :as string]
             [clojure.string :as string]
-            [promesa.core :as p]
-            [goog.object :as gobj]))
+            [promesa.core :as p]))
 
 
 (defn platform []
 (defn platform []
   (.getPlatform Capacitor))
   (.getPlatform Capacitor))
@@ -25,13 +23,7 @@
 
 
 (defonce folder-picker (registerPlugin "FolderPicker"))
 (defonce folder-picker (registerPlugin "FolderPicker"))
 (when (native-ios?)
 (when (native-ios?)
-  (defonce ios-utils (registerPlugin "Utils"))
-  (defonce ios-file-container (registerPlugin "FileContainer")))
-
-;; NOTE: both iOS and android share the same API
-(when (native-platform?)
-  (defonce file-sync FileSync)
-  (defonce fs-watcher (registerPlugin "FsWatcher")))
+  (defonce ios-utils (registerPlugin "Utils")))
 
 
 (defn hide-splash []
 (defn hide-splash []
   (.hide SplashScreen))
   (.hide SplashScreen))
@@ -99,14 +91,10 @@
   [path]
   [path]
   (string/includes? path "/iCloud~com~logseq~logseq/"))
   (string/includes? path "/iCloud~com~logseq~logseq/"))
 
 
-(defn is-iCloud-container-path?
-  "Check whether `path' is iCloud container path on iOS"
-  [path]
-  (re-matches #"/iCloud~com~logseq~logseq/Documents/?$" path))
-
-(defn app-active?
-  "Whether the app is active. This function returns a promise."
-  []
-  (let [app ^js (gobj/get Plugins "App")]
-    (p/let [state (.getState app)]
-      (gobj/get state "isActive"))))
+(comment
+  (defn app-active?
+    "Whether the app is active. This function returns a promise."
+    []
+    (let [app ^js (gobj/get Plugins "App")]
+      (p/let [state (.getState app)]
+        (gobj/get state "isActive")))))

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

@@ -122,15 +122,8 @@
 
 
 (defn <export-db!
 (defn <export-db!
   [repo data]
   [repo data]
-  (cond
-    (util/electron?)
-    (ipc/ipc :db-export repo data)
-
-    ;; TODO: browser nfs-supported? auto backup
-
-    ;;
-    :else
-    nil))
+  (when (util/electron?)
+    (ipc/ipc :db-export repo data)))
 
 
 (defn- sqlite-error-handler
 (defn- sqlite-error-handler
   [error]
   [error]

+ 0 - 15
src/main/frontend/state.cljs

@@ -71,7 +71,6 @@
       :notification/show?                    false
       :notification/show?                    false
       :notification/content                  nil
       :notification/content                  nil
       :repo/loading-files?                   {}
       :repo/loading-files?                   {}
-      :nfs/user-granted?                     {}
       :nfs/refreshing?                       nil
       :nfs/refreshing?                       nil
       :instrument/disabled?                  (storage/get "instrument-disabled")
       :instrument/disabled?                  (storage/get "instrument-disabled")
       ;; TODO: how to detect the network reliably?
       ;; TODO: how to detect the network reliably?
@@ -219,10 +218,6 @@
       :mobile/show-toolbar?                  false
       :mobile/show-toolbar?                  false
       :mobile/show-recording-bar?            false
       :mobile/show-recording-bar?            false
       :mobile/show-tabbar?                   false
       :mobile/show-tabbar?                   false
-;;; Used to monitor mobile app status,
-;;; value spec:
-;;; {:is-active? bool, :timestamp int}
-      :mobile/app-state-change                 (atom nil)
 
 
       ;; plugin
       ;; plugin
       :plugin/enabled                        (and util/plugin-platform?
       :plugin/enabled                        (and util/plugin-platform?
@@ -2229,12 +2224,6 @@ Similar to re-frame subscriptions"
                 (every? not-empty (vals agent-opts)))
                 (every? not-empty (vals agent-opts)))
       (str protocol "://" host ":" port))))
       (str protocol "://" host ":" port))))
 
 
-(defn set-mobile-app-state-change
-  [is-active?]
-  (set-state! :mobile/app-state-change
-              {:is-active? is-active?
-               :timestamp (inst-ms (js/Date.))}))
-
 (defn get-sync-graph-by-id
 (defn get-sync-graph-by-id
   [graph-uuid]
   [graph-uuid]
   (when graph-uuid
   (when graph-uuid
@@ -2280,10 +2269,6 @@ Similar to re-frame subscriptions"
   []
   []
   (:pdf/current @state))
   (:pdf/current @state))
 
 
-(defn nfs-user-granted?
-  [repo]
-  (get-in @state [:nfs/user-granted? repo]))
-
 (defn set-current-pdf!
 (defn set-current-pdf!
   [inflated-file]
   [inflated-file]
   (let [settle-file! #(set-state! :pdf/current inflated-file)]
   (let [settle-file! #(set-state! :pdf/current inflated-file)]

Некоторые файлы не были показаны из-за большого количества измененных файлов