Browse Source

Merge branch 'master' into mrtracy/ref_sync_fix

Gabriel Horner 3 năm trước cách đây
mục cha
commit
043fa90dab
51 tập tin đã thay đổi với 514 bổ sung395 xóa
  1. 77 0
      .github/workflows/build-ios-release.yml
  2. 1 1
      README.md
  3. 5 0
      docs/dev-practices.md
  4. 2 0
      ios/App/App/Info.plist
  5. 8 0
      ios/App/fastlane/Appfile
  6. 53 0
      ios/App/fastlane/Fastfile
  7. 13 0
      ios/App/fastlane/Matchfile
  8. 32 0
      ios/App/fastlane/README.md
  9. 0 1
      package.json
  10. 0 1
      public/index.html
  11. 0 1
      resources/electron.html
  12. 0 1
      resources/index.html
  13. 47 0
      scripts/patch-xcode-project.sh
  14. 0 6
      shadow-cljs.edn
  15. 1 1
      src/electron/electron/core.cljs
  16. 5 2
      src/main/electron/listener.cljs
  17. 7 3
      src/main/frontend/components/block.cljs
  18. 28 21
      src/main/frontend/components/conversion.cljs
  19. 1 3
      src/main/frontend/components/editor.cljs
  20. 11 11
      src/main/frontend/components/sidebar.cljs
  21. 3 7
      src/main/frontend/config.cljs
  22. 0 5
      src/main/frontend/dicts.cljc
  23. 2 10
      src/main/frontend/encrypt.cljs
  24. 0 23
      src/main/frontend/extensions/age_encryption.cljs
  25. 1 1
      src/main/frontend/extensions/pdf/highlights.cljs
  26. 3 1
      src/main/frontend/extensions/pdf/toolbar.cljs
  27. 5 7
      src/main/frontend/fs.cljs
  28. 3 3
      src/main/frontend/fs/capacitor_fs.cljs
  29. 105 91
      src/main/frontend/fs/sync.cljs
  30. 1 5
      src/main/frontend/handler.cljs
  31. 22 11
      src/main/frontend/handler/conversion.cljs
  32. 5 27
      src/main/frontend/handler/editor.cljs
  33. 19 9
      src/main/frontend/handler/events.cljs
  34. 6 10
      src/main/frontend/handler/file.cljs
  35. 0 44
      src/main/frontend/handler/image.cljs
  36. 6 4
      src/main/frontend/handler/repo.cljs
  37. 0 18
      src/main/frontend/image.cljs
  38. 8 7
      src/main/frontend/mobile/camera.cljs
  39. 2 4
      src/main/frontend/modules/instrumentation/sentry.cljs
  40. 6 5
      src/main/frontend/modules/outliner/core.cljs
  41. 2 5
      src/main/frontend/state.cljs
  42. 3 3
      src/main/frontend/ui.cljs
  43. 7 24
      src/main/frontend/util.cljc
  44. 1 1
      src/test/frontend/db/name_sanity_test.cljs
  45. 5 5
      templates/config.edn
  46. 1 1
      tldraw/README.md
  47. 1 1
      tldraw/apps/tldraw-logseq/src/lib/shapes/LineShape.tsx
  48. 2 2
      tldraw/apps/tldraw-logseq/src/lib/shapes/PencilShape.tsx
  49. 1 1
      tldraw/apps/tldraw-logseq/src/styles.css
  50. 3 3
      tldraw/packages/core/src/types/types.ts
  51. 0 5
      yarn.lock

+ 77 - 0
.github/workflows/build-ios-release.yml

@@ -0,0 +1,77 @@
+# This workflow build iOS App as a .ipa file and upload it to TestFlight.
+
+name: Build-iOS
+
+on:
+  workflow_dispatch:
+    inputs:
+      git-ref:
+        description: "Release Git Ref (Which branch or tag to build?)"
+        required: true
+        default: "master"
+
+env:
+  CLOJURE_VERSION: '1.10.1.763'
+  NODE_VERSION: '16'
+  JAVA_VERSION: '11'
+
+jobs:
+  build-app:
+    runs-on: macos-latest
+    steps:
+      - name: Check out Git repository
+        uses: actions/checkout@v2
+        with:
+          ref: ${{ github.event.inputs.git-ref }}
+
+      - name: Install Node.js, NPM and Yarn
+        uses: actions/setup-node@v2
+        with:
+          node-version: ${{ env.NODE_VERSION }}
+
+      - name: Setup Java JDK
+        uses: actions/setup-java@v2
+        with:
+          distribution: 'zulu'
+          java-version: ${{ env.JAVA_VERSION }}
+
+      - name: Cache clojure deps
+        uses: actions/cache@v2
+        with:
+          path: |
+            ~/.m2/repository
+            ~/.gitlibs
+          key: ${{ runner.os }}-clojure-lib-${{ hashFiles('**/deps.edn') }}
+
+      - name: Setup clojure
+        uses: DeLaGuardo/[email protected]
+        with:
+          cli: ${{ env.CLOJURE_VERSION }}
+
+      - name: Setup build tools
+        run: brew install fastlane
+
+      - name: Set Build Environment Variables
+        run: |
+          echo "ENABLE_FILE_SYNC_PRODUCTION=true" >> $GITHUB_ENV
+
+      - name: Compile CLJS
+        run: yarn install && yarn release-app
+
+      - name: Sync static build files
+        run: rsync -avz --exclude node_modules --exclude '*.js.map' --exclude android ./static/ ./public/static/
+
+      - name: Prepare iOS build
+        run: npx cap sync ios
+
+      - name: Build and upload iOS app
+        run: fastlane beta
+        working-directory: ./ios/App
+        env:
+          APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
+          APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
+          APP_STORE_CONNECT_API_KEY_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY }}
+          APP_STORE_CONNECT_API_KEY_IS_KEY_CONTENT_BASE64: true
+          SLACK_URL: ${{ secrets.SLACK_URL }}
+          MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
+          MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}

+ 1 - 1
README.md

@@ -92,7 +92,7 @@ If you would like to contribute by solving an open issue, please fork this repos
 
 Once you push your code to your fork you we'll be able to open a PR into Logseq repository. For more info you can follow this guide from [Github docs](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork)
 
-And here a list of some [good firt issues](https://github.com/logseq/logseq/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)!
+And here a list of some [good first issues](https://github.com/logseq/logseq/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)!
 
 ## Thanks
 

+ 5 - 0
docs/dev-practices.md

@@ -89,6 +89,11 @@ yarn electron-watch
 yarn e2e-test # or npx playwright test
 ```
 
+If e2e failed after first running:
+- `rm -rdf ~/.logseq`
+- `rm -rdf <repo dir>/tmp/`  
+- `rm -rdf <appData dir>/Electron`  (Reference: https://www.electronjs.org/de/docs/latest/api/app#appgetpathname)
+
 ### Unit Testing
 
 Our unit tests use the [shadow-cljs test-runner](https://shadow-cljs.github.io/docs/UsersGuide.html#_testing). To run them:

+ 2 - 0
ios/App/App/Info.plist

@@ -107,5 +107,7 @@
 	<true/>
 	<key>UIViewControllerBasedStatusBarAppearance</key>
 	<true/>
+	<key>ITSAppUsesNonExemptEncryption</key>
+	<false/>
 </dict>
 </plist>

+ 8 - 0
ios/App/fastlane/Appfile

@@ -0,0 +1,8 @@
+app_identifier("com.logseq.logseq") # The bundle identifier of your app
+apple_id("[email protected]") # Your Apple Developer Portal username
+
+itc_team_id("123783177") # App Store Connect Team ID
+team_id("K378MFWK59") # Developer Portal Team ID
+
+# For more information about the Appfile, see:
+#     https://docs.fastlane.tools/advanced/#appfile

+ 53 - 0
ios/App/fastlane/Fastfile

@@ -0,0 +1,53 @@
+# This file contains the fastlane.tools configuration
+# You can find the documentation at https://docs.fastlane.tools
+#
+# For a list of all available actions, check out
+#
+#     https://docs.fastlane.tools/actions
+#
+# For a list of all available plugins, check out
+#
+#     https://docs.fastlane.tools/plugins/available-plugins
+#
+
+# Uncomment the line if you want fastlane to automatically update itself
+# update_fastlane
+
+default_platform(:ios)
+
+platform :ios do
+  desc "Push a new beta build to TestFlight"
+  lane :beta do
+    setup_ci
+
+    app_store_connect_api_key(
+      key_id: ENV["APP_STORE_CONNECT_API_KEY_KEY_ID"],
+      issuer_id: ENV["APP_STORE_CONNECT_API_KEY_ISSUER_ID"],
+      key_filepath: ENV["APP_STORE_CONNECT_API_KEY_KEY_FILEPATH"],
+    )
+
+    sync_code_signing(type: "appstore", readonly: true)
+
+    build_number = increment_build_number(
+      xcodeproj: "App.xcodeproj",
+      build_number: latest_testflight_build_number + 1,
+    )
+
+    # Ref: https://docs.fastlane.tools/advanced/fastlane/#directory-behavior
+    sh("../../../scripts/patch-xcode-project.sh")
+
+    build_app(
+      workspace: "App.xcworkspace",
+      destination: "generic/platform=iOS",
+      scheme: "Logseq",
+      configuration: "Release",
+    )
+
+    upload_to_testflight(
+      skip_submission: true,
+      skip_waiting_for_build_processing: true,
+    )
+
+    slack(message: "App Build (#{build_number}) successfully uploaded to TestFlight 🎉!")
+  end
+end

+ 13 - 0
ios/App/fastlane/Matchfile

@@ -0,0 +1,13 @@
+git_url("https://github.com/logseq/certificates.git")
+
+storage_mode("git")
+
+type("appstore") # The default type, can be: appstore, adhoc, enterprise or development
+
+app_identifier(["com.logseq.logseq", "com.logseq.logseq.ShareViewController"])
+# username("[email protected]") # Your Apple Developer Portal username
+
+# For all available options run `fastlane match --help`
+# Remove the # in the beginning of the line to enable the other options
+
+# The docs are available on https://docs.fastlane.tools/actions/match

+ 32 - 0
ios/App/fastlane/README.md

@@ -0,0 +1,32 @@
+fastlane documentation
+----
+
+# Installation
+
+Make sure you have the latest version of the Xcode command line tools installed:
+
+```sh
+xcode-select --install
+```
+
+For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
+
+# Available Actions
+
+## iOS
+
+### ios beta
+
+```sh
+[bundle exec] fastlane ios beta
+```
+
+Push a new beta build to TestFlight
+
+----
+
+This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
+
+More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
+
+The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).

+ 0 - 1
package.json

@@ -91,7 +91,6 @@
         "@capawesome/capacitor-background-task": "^2.0.0",
         "@excalidraw/excalidraw": "0.12.0",
         "@hugotomazi/capacitor-navigation-bar": "^2.0.0",
-        "@kanru/rage-wasm": "^0.3.0",
         "@logseq/capacitor-file-sync": "0.0.14",
         "@logseq/react-tweet-embed": "1.3.1-1",
         "@sentry/react": "^6.18.2",

+ 0 - 1
public/index.html

@@ -53,7 +53,6 @@
 <script defer src="/static/js/main.js"></script>
 <script defer src="/static/js/tabler.min.js"></script>
 <script defer src="/static/js/code-editor.js"></script>
-<script defer src="/static/js/age-encryption.js"></script>
 <script defer src="/static/js/tldraw.js"></script>
 <script defer src="/static/js/excalidraw.js"></script>
 </body>

+ 0 - 1
resources/electron.html

@@ -54,7 +54,6 @@ const portal = new MagicPortal(worker);
 <script defer src="./js/main.js"></script>
 <script defer src="./js/tabler.min.js"></script>
 <script defer src="./js/code-editor.js"></script>
-<script defer src="./js/age-encryption.js"></script>
 <script defer src="./js/excalidraw.js"></script>
 <script defer src="./js/tldraw.js"></script>
 </body>

+ 0 - 1
resources/index.html

@@ -53,7 +53,6 @@ const portal = new MagicPortal(worker);
 <script defer src="./js/main.js"></script>
 <script defer src="./js/tabler.min.js"></script>
 <script defer src="./js/code-editor.js"></script>
-<script defer src="./js/age-encryption.js"></script>
 <script defer src="./js/excalidraw.js"></script>
 <script defer src="./js/tldraw.js"></script>
 </body>

+ 47 - 0
scripts/patch-xcode-project.sh

@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# This script patches the iOS project to use the correct codesigning and provisioning profiles.
+
+set -e
+set -o pipefail
+
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+
+cd ${SCRIPT_DIR}/../ios/App
+
+ls -lah App.xcodeproj/project.pbxproj
+
+FILE="App.xcodeproj/project.pbxproj"
+
+/usr/libexec/PlistBuddy -c 'Set :objects:504EC2FC1FED79650016851F:attributes:TargetAttributes:504EC3031FED79650016851F:ProvisioningStyle Manual' $FILE
+/usr/libexec/PlistBuddy -c 'Set :objects:504EC2FC1FED79650016851F:attributes:TargetAttributes:5FFF7D6927E343FA00B00DA8:ProvisioningStyle Manual' $FILE
+
+/usr/libexec/PlistBuddy -c 'Set :objects:504EC3171FED79650016851F:buildSettings:CODE_SIGN_STYLE Manual' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:504EC3171FED79650016851F:buildSettings:"CODE_SIGN_IDENTITY[sdk=iphoneos*]" String "iPhone Distribution"' $FILE
+/usr/libexec/PlistBuddy -c 'Set :objects:504EC3171FED79650016851F:buildSettings:DEVELOPMENT_TEAM ""' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:504EC3171FED79650016851F:buildSettings:"DEVELOPMENT_TEAM[sdk=iphoneos*]" String K378MFWK59' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:504EC3171FED79650016851F:buildSettings:PROVISIONING_PROFILE_SPECIFIER String ""' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:504EC3171FED79650016851F:buildSettings:"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" String "match AppStore com.logseq.logseq"' $FILE
+
+/usr/libexec/PlistBuddy -c 'Set :objects:504EC3181FED79650016851F:buildSettings:CODE_SIGN_STYLE Manual' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:504EC3181FED79650016851F:buildSettings:"CODE_SIGN_IDENTITY[sdk=iphoneos*]" String "iPhone Distribution"' $FILE
+/usr/libexec/PlistBuddy -c 'Set :objects:504EC3181FED79650016851F:buildSettings:DEVELOPMENT_TEAM ""' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:504EC3181FED79650016851F:buildSettings:"DEVELOPMENT_TEAM[sdk=iphoneos*]" String K378MFWK59' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:504EC3181FED79650016851F:buildSettings:PROVISIONING_PROFILE_SPECIFIER String ""' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:504EC3181FED79650016851F:buildSettings:"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" String "match AppStore com.logseq.logseq"' $FILE
+
+/usr/libexec/PlistBuddy -c 'Set :objects:5FFF7D7627E343FA00B00DA8:buildSettings:CODE_SIGN_STYLE Manual' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:5FFF7D7627E343FA00B00DA8:buildSettings:"CODE_SIGN_IDENTITY[sdk=iphoneos*]" String "iPhone Distribution"' $FILE
+/usr/libexec/PlistBuddy -c 'Set :objects:5FFF7D7627E343FA00B00DA8:buildSettings:DEVELOPMENT_TEAM ""' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:5FFF7D7627E343FA00B00DA8:buildSettings:"DEVELOPMENT_TEAM[sdk=iphoneos*]" String K378MFWK59' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:5FFF7D7627E343FA00B00DA8:buildSettings:PROVISIONING_PROFILE_SPECIFIER String ""' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:5FFF7D7627E343FA00B00DA8:buildSettings:"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" String "match AppStore com.logseq.logseq.ShareViewController"' $FILE
+
+/usr/libexec/PlistBuddy -c 'Set :objects:5FFF7D7727E343FA00B00DA8:buildSettings:CODE_SIGN_STYLE Manual' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:5FFF7D7727E343FA00B00DA8:buildSettings:"CODE_SIGN_IDENTITY[sdk=iphoneos*]" String "iPhone Distribution"' $FILE
+/usr/libexec/PlistBuddy -c 'Set :objects:5FFF7D7727E343FA00B00DA8:buildSettings:DEVELOPMENT_TEAM ""' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:5FFF7D7727E343FA00B00DA8:buildSettings:"DEVELOPMENT_TEAM[sdk=iphoneos*]" String K378MFWK59' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:5FFF7D7727E343FA00B00DA8:buildSettings:PROVISIONING_PROFILE_SPECIFIER String ""' $FILE
+/usr/libexec/PlistBuddy -c 'Add :objects:5FFF7D7727E343FA00B00DA8:buildSettings:"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" String "match AppStore com.logseq.logseq.ShareViewController"' $FILE
+
+echo Patch OK!

+ 0 - 6
shadow-cljs.edn

@@ -16,9 +16,6 @@
                         :code-editor
                         {:entries    [frontend.extensions.code]
                          :depends-on #{:main}}
-                        :age-encryption
-                        {:entries    [frontend.extensions.age-encryption]
-                         :depends-on #{:main}}
                         :excalidraw
                         {:entries    [frontend.extensions.excalidraw]
                          :depends-on #{:main}}
@@ -83,9 +80,6 @@
                                :code-editor
                                {:entries    [frontend.extensions.code]
                                 :depends-on #{:main}}
-                               :age-encryption
-                               {:entries    [frontend.extensions.age-encryption]
-                                :depends-on #{:main}}
                                :excalidraw
                                {:entries    [frontend.extensions.excalidraw]
                                 :depends-on #{:main}}

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

@@ -137,7 +137,7 @@
                 ;; TODO: ugly, replace with ls-files and filter with ".map"
                 _ (p/all (map (fn [file]
                                 (. fs removeSync (path/join static-dir "js" (str file ".map"))))
-                              ["main.js" "code-editor.js" "excalidraw.js" "age-encryption.js"]))]
+                              ["main.js" "code-editor.js" "excalidraw.js"]))]
 
           (send-to-renderer
            :notification

+ 5 - 2
src/main/electron/listener.cljs

@@ -158,7 +158,10 @@
                      (fn [args]
                        (let [{:keys [url title content page append]} (bean/->clj args)
                              insert-today? (get-in (state/get-config)
-                                                   [:quick-capture-options :insert-today]
+                                                   [:quick-capture-options :insert-today?]
+                                                   false)
+                             redirect-page? (get-in (state/get-config)
+                                                   [:quick-capture-options :redirect-page?]
                                                    false)
                              today-page (when (state/enable-journals?)
                                           (string/lower-case (date/today)))
@@ -195,7 +198,7 @@
 
                            (do
                              (when (not= page (state/get-current-page))
-                               (page-handler/create! page {:redirect? true}))
+                               (page-handler/create! page {:redirect? redirect-page?}))
                              (editor-handler/api-insert-new-block! content {:page page
                                                                             :edit-block? true
                                                                             :replace-empty-target? true}))))))

+ 7 - 3
src/main/frontend/components/block.cljs

@@ -385,8 +385,12 @@
             share-fn (fn [event]
                        (util/stop event)
                        (when (mobile-util/native-platform?)
-                         (.share Share #js {:url path
-                                            :title "Open file with your favorite app"})))]
+                         ;; File URL must be legal, so filename muse be URI-encoded
+                         (let [[rel-dir basename] (util/get-dir-and-basename href)
+                               basename (js/encodeURIComponent basename)
+                               asset-url (str repo-dir rel-dir "/" basename)]
+                           (.share Share (clj->js {:url asset-url
+                                                   :title "Open file with your favorite app"})))))]
 
         (cond
           (contains? config/audio-formats ext)
@@ -401,7 +405,7 @@
           [:a.asset-ref.is-plaintext {:href (rfe/href :file {:path path})
                                       :on-click (fn [_event]
                                                   (p/let [result (fs/read-file repo-dir path)]
-                                                    (db/set-file-content! repo path result )))}
+                                                    (db/set-file-content! repo path result)))}
            title]
 
           (= ext :pdf)

+ 28 - 21
src/main/frontend/components/conversion.cljs

@@ -13,6 +13,7 @@
             [frontend.context.i18n :refer [t]]
             [rum.core :as rum]
             [frontend.handler.file-sync :as file-sync-handler]
+            [frontend.fs.sync :as sync]
             [frontend.handler.notification :as notification]))
 
 (defn- ask-for-re-index
@@ -28,15 +29,26 @@
 
 (defn- <close-modal-on-done
   "Ask users to re-index when the modal is exited"
-  [sync?]
-  (async/go (state/close-settings!)
-            (async/<! (async/timeout 100)) ;; modal race condition requires investigation
-            (if sync?
-              (notification/show!
-               [:div "Please re-index this graph after all the changes are synced."]
-               :warning
-               false)
-              (ask-for-re-index))))
+  [sync? rename-items]
+  (async/go
+    (state/close-modal!)
+    (async/<! (async/timeout 100)) ;; modal race condition requires investigation
+    (let [renamed-paths (keep (fn [{:keys [file file-name target]}]
+                                (when (not= file-name target)
+                                  (sync/relative-path (:file/path file)))) rename-items)
+          graph-txid (second @sync/graphs-txid)]
+      (when (and (seq renamed-paths) sync? graph-txid)
+        (async/<!
+         (sync/<delete-remote-files-control
+          sync/remoteapi
+          graph-txid
+          renamed-paths))))
+    (if sync?
+      (notification/show!
+       [:div "Please re-index this graph after all the changes are synced."]
+       :warning
+       false)
+      (ask-for-re-index))))
 
 (rum/defc legacy-warning
   [repo *target-format *dir-format *solid-format]
@@ -123,10 +135,11 @@
                                         (merge ret {:page page :file file}))))
                                (remove nil?))
             sync? (file-sync-handler/current-graph-sync-on?)
-            <rename-all   #(async/go (doseq [{:keys [file target status]} rename-items]
-                                       (when (not= status :unreachable)
-                                         (async/<! (p->c (page-handler/rename-file! file target (constantly nil) true)))))
-                                     (<close-modal-on-done sync?))]
+            <rename-all   #(async/go
+                             (doseq [{:keys [file target status]} rename-items]
+                               (when (not= status :unreachable)
+                                 (async/<! (p->c (page-handler/rename-file! file target (constantly nil) true)))))
+                             (<close-modal-on-done sync? rename-items))]
 
         (if (not-empty rename-items)
           [:div ;; Normal UX stage 2: close stage 1 UI, show the action description as admolition
@@ -154,12 +167,7 @@
                      rename-fn      #(page-handler/rename-file! file target rm-item-fn)
                      rename-but     [:a {:on-click rename-fn
                                          :title (t :file-rn/apply-rename)}
-                                     [:span (t :file-rn/rename src-file-name tgt-file-name)]]
-                     rename-but-sm  (ui/button
-                                     (t :file-rn/rename-sm)
-                                     :on-click rename-fn
-                                     :class "text-sm p-1 mr-1"
-                                     :style {:word-break "normal"})]
+                                     [:span (t :file-rn/rename src-file-name tgt-file-name)]]]
                  [:tr {:key (:block/name page)}
                   [:td [:div [:p "📄 " old-title]]
                    (case status
@@ -168,6 +176,5 @@
                       [:p (t :file-rn/otherwise-breaking) " \"" changed-title \"]]
                      :unreachable
                      [:div [:p "🔴 " (t :file-rn/unreachable-title changed-title)]]
-                     [:div [:p "🟢 " (t :file-rn/optional-rename) rename-but]])]
-                  [:td rename-but-sm]]))]]]
+                     [:div [:p "🟢 " (t :file-rn/optional-rename) rename-but]])]]))]]]
           [:div "🎉 " (t :file-rn/no-action)]))]]))

+ 1 - 3
src/main/frontend/components/editor.cljs

@@ -76,9 +76,7 @@
                                    (not (contains? #{"Date picker" "Template" "Deadline" "Scheduled" "Upload an image"} command))))]
               (editor-handler/insert-command! id command-steps
                                               format
-                                              {:restore? restore-slash?})
-              (state/pub-event! [:instrument {:type :editor/command-triggered
-                                              :payload {:command command}}]))))
+                                              {:restore? restore-slash?}))))
         :class
         "black"}))))
 

+ 11 - 11
src/main/frontend/components/sidebar.cljs

@@ -361,7 +361,16 @@
                                      (route-handler/sidebar-journals!)
                                      (route-handler/go-to-journals!)))
                :icon             "calendar"})))
-
+         
+         (when enable-whiteboards?
+           (sidebar-item
+            {:class           "whiteboard"
+             :title           (t :right-side-bar/whiteboards)
+             :href            (rfe/href :whiteboards)
+             :active          (and (not srs-open?) (#{:whiteboard :whiteboards} route-name))
+             :icon            "whiteboard"
+             :icon-extension? true}))
+         
          (when (state/enable-flashcards? (state/get-current-repo))
            [:div.flashcards-nav
             (flashcards srs-open?)])
@@ -378,16 +387,7 @@
            :title  (t :right-side-bar/all-pages)
            :href   (rfe/href :all-pages)
            :active (and (not srs-open?) (= route-name :all-pages))
-           :icon   "files"})
-
-         (when enable-whiteboards?
-           (sidebar-item
-            {:class           "whiteboard"
-             :title           (t :right-side-bar/whiteboards)
-             :href            (rfe/href :whiteboards)
-             :active          (and (not srs-open?) (#{:whiteboard :whiteboards} route-name))
-             :icon            "whiteboard"
-             :icon-extension? true}))]]
+           :icon   "files"})]]
 
        [:div.nav-contents-container.flex.flex-col.gap-1.pt-1
         {:on-scroll on-contents-scroll}

+ 3 - 7
src/main/frontend/config.cljs

@@ -66,11 +66,6 @@
     "http://localhost:3000"
     (util/format "https://%s.com" app-name)))
 
-(def api
-  (if dev?
-    "http://localhost:3000/api/v1/"
-    (str website "/api/v1/")))
-
 (def asset-domain (util/format "https://asset.%s.com"
                                app-name))
 
@@ -112,7 +107,8 @@
   ([input] (extname-of-supported?
             input
             [image-formats doc-formats audio-formats
-             video-formats markup-formats html-render-formats]))
+             video-formats markup-formats html-render-formats
+             (gp-config/text-formats)]))
   ([input formats]
    (when-let [input (some->
                      (cond-> input
@@ -131,7 +127,7 @@
    *** Warning!!! ***
    For UX logic only! Don't use for FS logic
    iPad / Android Pad doesn't trigger!
-   
+
    Same as config/mobile?"
   (when-not util/node-test?
     (util/safe-re-find #"Mobi" js/navigator.userAgent)))

+ 0 - 5
src/main/frontend/dicts.cljc

@@ -132,7 +132,6 @@
         :file-rn/all-action "Apply all Actions!"
         :file-rn/select-format "(Developer Mode Option, Dangerous!) Select filename format"
         :file-rn/rename "rename file \"{1}\" to \"{2}\""
-        :file-rn/rename-sm "Rename"
         :file-rn/apply-rename "Apply the file rename operation"
         :file-rn/affected-pages "Affected Pages after the format change"
         :file-rn/suggest-rename "Action required: "
@@ -1273,7 +1272,6 @@
         :file-rn/otherwise-breaking "Ou le titre deviendra"
         :file-rn/re-index "La réindexation est fortement recommandée après que les fichiers aient été renommés, puis sur les autres postes après synchronisation."
         :file-rn/rename "renommer le fichier \"{1}\" en \"{2}\""
-        :file-rn/rename-sm "Renommer"
         :file-rn/select-confirm-proceed "Dev: format d'écriture"
         :file-rn/select-format "(Option du Mode Developpeur, Danger !) Sélectionnez le format de nom de fichier"
         :file-rn/suggest-rename "Action requise : "
@@ -1585,7 +1583,6 @@
            :file-rn/all-action "应用所有操作!"
            :file-rn/select-format "(开发者模式选项,危险!) 选择文件名格式"
            :file-rn/rename "重命名文件 \"{1}\" 到 \"{2}\""
-           :file-rn/rename-sm "重命名"
            :file-rn/apply-rename "应用文件重命名操作"
            :file-rn/affected-pages "格式改变后,影响的文件"
            :file-rn/suggest-rename "需要的操作: "
@@ -2270,7 +2267,6 @@
         :file-rn/all-action "¡Aplicar todas las acciones!"
         :file-rn/select-format "(Opción modo desarrollador, ¡peligroso!) Seccione el formato de nombre de archivo"
         :file-rn/rename "Renombrar \"{1}\" a \"{2}\""
-        :file-rn/rename-sm "Renombrar"
         :file-rn/apply-rename "Aplicar la operación de cambio de nombre de archivo"
         :file-rn/affected-pages "Páginas afectadas después del cambio de formato"
         :file-rn/suggest-rename "Acción necesaria: "
@@ -4620,7 +4616,6 @@
         :file-rn/all-action "Tüm Eylemleri Uygula!"
         :file-rn/select-format "(Geliştirici Modu Seçeneği, Tehlikeli!) Dosya adı biçimini seçin"
         :file-rn/rename "\"{1}\" dosyasını \"{2}\" olarak yeniden adlandır"
-        :file-rn/rename-sm "Yeniden adlandır"
         :file-rn/apply-rename "Dosya yeniden adlandırma işlemini uygula"
         :file-rn/affected-pages "Biçim değişikliğinden sonra Etkilenen Sayfalar"
         :file-rn/suggest-rename "Eylem gereklidir: "

+ 2 - 10
src/main/frontend/encrypt.cljs

@@ -4,7 +4,6 @@
             [frontend.util :as util]
             [promesa.core :as p]
             [electron.ipc :as ipc]
-            [shadow.loader :as loader]
             [frontend.mobile.util :as mobile-util]))
 
 (defn encrypt-with-passphrase
@@ -22,10 +21,7 @@
              :data)
 
     :else
-    (p/let [lazy-encrypt-with-user-passphrase (resolve 'frontend.extensions.age-encryption/encrypt-with-user-passphrase)
-            content (utf8/encode content)
-            encrypted (@lazy-encrypt-with-user-passphrase passphrase content true)]
-      (utf8/decode encrypted))))
+    nil))
 
 (defn decrypt-with-passphrase
   [passphrase content]
@@ -42,8 +38,4 @@
              :data)
 
     :else
-    (p/let [_ (loader/load :age-encryption)
-            lazy-decrypt-with-user-passphrase (resolve 'frontend.extensions.age-encryption/decrypt-with-user-passphrase)
-            content (utf8/encode content)
-            decrypted (lazy-decrypt-with-user-passphrase passphrase content)]
-      (utf8/decode decrypted))))
+    nil))

+ 0 - 23
src/main/frontend/extensions/age_encryption.cljs

@@ -1,23 +0,0 @@
-(ns frontend.extensions.age-encryption
-  (:require ["regenerator-runtime/runtime"] ;; required for async npm module
-            ["@kanru/rage-wasm" :as rage]))
-
-(defn keygen
-  []
-  (rage/keygen))
-
-(defn encrypt-with-x25519
-  [public-key content armor]
-  (rage/encrypt_with_x25519 public-key content armor))
-
-(defn decrypt-with-x25519
-  [secret-key content]
-  (rage/decrypt_with_x25519 secret-key content))
-
-(defn encrypt-with-user-passphrase
-  [passphrase content armor]
-  (rage/encrypt_with_user_passphrase passphrase content armor))
-
-(defn decrypt-with-user-passphrase
-  [passphrase content]
-  (rage/decrypt_with_user_passphrase passphrase content))

+ 1 - 1
src/main/frontend/extensions/pdf/highlights.cljs

@@ -178,7 +178,7 @@
                     (action-fn! action true)))}
 
      [:li.item-colors
-      (for [it ["yellow", "blue", "green", "red", "purple"]]
+      (for [it ["yellow", "red", "green", "blue", "purple"]]
         [:a {:key it :data-color it :data-action it} it])]
 
 

+ 3 - 1
src/main/frontend/extensions/pdf/toolbar.cljs

@@ -519,6 +519,8 @@
         [:span.nu.flex.items-center.opacity-70
          [:input {:ref            *page-ref
                   :type           "number"
+                  :min            1
+                  :max            total-page-num
                   :class          (util/classnames [{:is-long (> (util/safe-parse-int current-page-num) 999)}])
                   :default-value  current-page-num
                   :on-mouse-enter #(.select ^js (.-target %))
@@ -553,4 +555,4 @@
         viewer-theme
         {:t              t
          :hide-settings! #(set-settings-visible! false)
-         :select-theme!  #(set-viewer-theme! %)}))]))
+         :select-theme!  #(set-viewer-theme! %)}))]))

+ 5 - 7
src/main/frontend/fs.cljs

@@ -82,13 +82,11 @@
        (p/let [opts (assoc opts
                            :error-handler
                            (fn [error]
-                             (state/pub-event! [:instrument {:type :write-file/failed
-                                                             :payload {:fs (type fs-record)
-                                                                       :user-agent (when js/navigator js/navigator.userAgent)
-                                                                       :path path
-                                                                       :content-length (count content)
-                                                                       :error-str (str error)
-                                                                       :error error}}])))
+                             (state/pub-event! [:capture-error {:error error
+                                                                :payload {:type :write-file/failed
+                                                                          :fs (type fs-record)
+                                                                          :user-agent (when js/navigator js/navigator.userAgent)
+                                                                          :content-length (count content)}}])))
                _ (protocol/write-file! (get-fs dir) repo dir path content opts)]
          (when (= bfs-record fs-record)
            (db/set-file-last-modified-at! repo (config/get-file-path repo path) (js/Date.))))

+ 3 - 3
src/main/frontend/fs/capacitor_fs.cljs

@@ -229,9 +229,9 @@
 
       :else
       (do
-        (state/pub-event! [:instrument {:type :error/ios-path-missing-slashes
-                                        ;; respect user's privacy
-                                        :path (gp-util/safe-subs path 10)}])
+        (state/pub-event! [:capture-error {:error (js/Error. "ios path missing slashes")
+                                           :payload {:type :error/ios-path-missing-slashes
+                                                     :path (gp-util/safe-subs (str path) 12)}}])
         path))
     path))
 

+ 105 - 91
src/main/frontend/fs/sync.cljs

@@ -494,7 +494,8 @@
         reserved-paths (filter f paths)]
     (when (seq reserved-paths)
       (let [paths (if path-string? reserved-paths (map -relative-path reserved-paths))]
-        (state/pub-event! [:ui/notify-outdated-filename-format paths])
+        (when (seq paths)
+          (state/pub-event! [:ui/notify-outdated-filename-format paths]))
         (prn "Skipped uploading those file paths with reserved chars: " paths)))
     (vec (remove f paths))))
 
@@ -728,6 +729,12 @@
   (<get-graph-encrypt-keys [this graph-uuid])
   (<upload-graph-encrypt-keys [this graph-uuid public-key encrypted-private-key]))
 
+
+(defprotocol IRemoteControlAPI
+  "api functions provided for outside the sync process"
+  (<delete-remote-files-control [this graph-uuid filepaths])
+  )
+
 (defprotocol IToken
   (<get-token [this]))
 
@@ -744,7 +751,6 @@
       (when (some-> r first :path (not= filepath))
         (-> r first :path)))))
 
-
 (defn <local-file-not-exist?
   [graph-uuid irsapi base-path filepath]
   (go
@@ -772,6 +778,22 @@
 
 (declare <rsapi-cancel-all-requests)
 
+(defn- build-local-file-metadatas
+  [this graph-uuid result]
+  (loop [[[path metadata] & others] (js->clj result)
+         result #{}]
+    (if-not (and path metadata)
+      ;; finish
+      result
+      (let [normalized-path (path-normalize path)
+            encryptedFname (if (not= path normalized-path)
+                             (first (<! (<encrypt-fnames this graph-uuid [normalized-path])))
+                             (get metadata "encryptedFname"))]
+        (recur others
+               (conj result
+                     (->FileMetadata (get metadata "size") (get metadata "md5") normalized-path
+                                     encryptedFname (get metadata "mtime") false nil)))))))
+
 (deftype RSAPI [^:mutable graph-uuid' ^:mutable private-key' ^:mutable public-key']
   IToken
   (<get-token [_this]
@@ -789,26 +811,17 @@
     (set! private-key' private-key)
     (set! public-key' public-key)
     (p->c (ipc/ipc "set-env" graph-uuid (if prod? "prod" "dev") private-key public-key)))
-  (<get-local-all-files-meta [_ graph-uuid base-path]
+  (<get-local-all-files-meta [this graph-uuid base-path]
     (go
       (let [r (<! (<retry-rsapi #(p->c (ipc/ipc "get-local-all-files-meta" graph-uuid base-path))))]
         (if (instance? ExceptionInfo r)
           r
-          (->> r
-               js->clj
-               (map (fn [[path metadata]]
-                      (->FileMetadata (get metadata "size") (get metadata "md5") (path-normalize path)
-                                      (get metadata "encryptedFname") (get metadata "mtime") false nil)))
-               set)))))
-  (<get-local-files-meta [_ graph-uuid base-path filepaths]
+          (build-local-file-metadatas this graph-uuid r)))))
+  (<get-local-files-meta [this graph-uuid base-path filepaths]
     (go
       (let [r (<! (<retry-rsapi #(p->c (ipc/ipc "get-local-files-meta" graph-uuid base-path filepaths))))]
         (assert (not (instance? ExceptionInfo r)) "get-local-files-meta shouldn't return exception")
-        (->> r
-             js->clj
-             (map (fn [[path metadata]]
-                    (->FileMetadata (get metadata "size") (get metadata "md5") (path-normalize path)
-                                    (get metadata "encryptedFname") (get metadata "mtime") false nil)))))))
+        (build-local-file-metadatas this graph-uuid r))))
   (<rename-local-file [_ graph-uuid base-path from to]
     (<retry-rsapi #(p->c (ipc/ipc "rename-local-file" graph-uuid base-path
                                   (path-normalize from)
@@ -881,36 +894,22 @@
                                                    :secretKey secret-key
                                                    :publicKey public-key}))))
 
-  (<get-local-all-files-meta [_ graph-uuid base-path]
+  (<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}))))]
         (if (instance? ExceptionInfo r)
           r
-          (->> (.-result r)
-               js->clj
-               (map (fn [[path metadata]]
-                      (->FileMetadata (get metadata "size") (get metadata "md5")
-                                      ;; return decoded path, keep it consistent with RSAPI
-                                      (path-normalize path)
-                                      (get metadata "encryptedFname") (get metadata "mtime") false nil)))
-               set)))))
-
-  (<get-local-files-meta [_ graph-uuid base-path filepaths]
+          (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")
-        (->> (.-result r)
-             js->clj
-             (map (fn [[path metadata]]
-                    (->FileMetadata (get metadata "size") (get metadata "md5")
-                                    ;; return decoded path, keep it consistent with RSAPI
-                                    (path-normalize path)
-                                    (get metadata "encryptedFname") (get metadata "mtime") false nil)))
-             set))))
+        (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
@@ -1169,10 +1168,7 @@
     (loop [[raw-path & other-paths] raw-paths]
       (when raw-path
         (let [normalized-path (path-normalize raw-path)]
-          (when (and (not= normalized-path raw-path)
-                     (get path->encrypted-path-map normalized-path))
-            ;; raw-path is un-normalized path and there are related normalized version one,
-            ;; then filter out this raw-path
+          (when (not= normalized-path raw-path)
             (println :filter-files-with-unnormalized-path raw-path)
             (conj! *encrypted-paths-to-drop (get path->encrypted-path-map raw-path))))
         (recur other-paths)))
@@ -1222,7 +1218,7 @@
                 (mapv
                  #(->FileMetadata (:size %)
                                   (:checksum %)
-                                  (path-normalize (get encrypted-path->path-map (:encrypted-path %)))
+                                  (get encrypted-path->path-map (:encrypted-path %))
                                   (:encrypted-path %)
                                   (:last-modified %)
                                   true nil)
@@ -1360,6 +1356,23 @@
                                                       :public-key            public-key
                                                       :encrypted-private-key encrypted-private-key})))))
 
+(extend-type RemoteAPI
+  IRemoteControlAPI
+  (<delete-remote-files-control [this graph-uuid filepaths]
+    (user/<wrap-ensure-id&access-token
+     (let [partitioned-files (partition-all 20 (<! (<encrypt-fnames rsapi graph-uuid filepaths)))]
+       (loop [[files & others] partitioned-files]
+         (when files
+           (let [current-txid (:TXId (<! (<get-remote-graph this nil graph-uuid)))]
+             (<! (.<request this "delete_files" {:GraphUUID graph-uuid :TXId current-txid :Files files}))
+             (recur others))))))))
+
+(comment
+  (declare remoteapi)
+  (<delete-remote-files-control remoteapi (second @graphs-txid) ["pages/aa.md"])
+
+  )
+
 (def remoteapi (->RemoteAPI nil))
 
 
@@ -1733,7 +1746,6 @@
                                     (<! (<get-local-files-meta
                                          rsapi (:current-syncing-graph-uuid sync-state) dir [path])))
                     checksum (and (coll? files-meta) (some-> files-meta first :etag))]
-                (println :files-watch (->FileChangeEvent type dir path stat checksum))
                 (>! local-changes-chan (->FileChangeEvent type dir path stat checksum))))))))))
 
 (defn local-changes-revised-chan-builder
@@ -1762,7 +1774,9 @@
             ;; add 2 simulated file-watcher events
             (>! ch (->FileChangeEvent "unlink" repo-dir (:old-path rename-event*) nil nil))
             (>! ch (->FileChangeEvent "add" repo-dir (:new-path rename-event*)
-                                      {:mtime (tc/to-long (t/now))} "fake-checksum"))
+                                      {:mtime (tc/to-long (t/now))
+                                       :size 1 ; add a fake size
+                                       } "fake-checksum"))
             (recur))
           local-change
           (cond
@@ -2003,11 +2017,6 @@
   (chan 1))
 (def full-sync-mult (async/mult full-sync-chan))
 
-(def stop-sync-chan
-  "offer `true` to this chan will stop current `SyncManager`"
-  (chan 1))
-(def stop-sync-mult (async/mult stop-sync-chan))
-
 (def remote->local-sync-chan
   "offer `true` to this chan will trigger a remote->local sync"
   (chan 1))
@@ -2633,13 +2642,13 @@
 ;;; ### put all stuff together
 
 (defrecord ^:large-vars/cleanup-todo
-  SyncManager [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
                ^:mutable ratelimit-local-changes-chan
                *txid ^:mutable state ^:mutable remote-change-chan ^:mutable *ws *stopped? *paused?
                ^:mutable ops-chan
                ;; control chans
-               private-full-sync-chan private-stop-sync-chan private-remote->local-sync-chan
+               private-full-sync-chan private-remote->local-sync-chan
                private-remote->local-full-sync-chan private-pause-resume-chan]
   Object
   (schedule [this next-state args reason]
@@ -2674,30 +2683,30 @@
     (set! ratelimit-local-changes-chan (<ratelimit local->remote-syncer local-changes-revised-chan))
     (setup-local->remote! local->remote-syncer)
     (async/tap full-sync-mult private-full-sync-chan)
-    (async/tap stop-sync-mult private-stop-sync-chan)
     (async/tap remote->local-sync-mult private-remote->local-sync-chan)
     (async/tap remote->local-full-sync-mult private-remote->local-full-sync-chan)
     (async/tap pause-resume-mult private-pause-resume-chan)
     (go-loop []
-      (let [{:keys [stop remote->local remote->local-full-sync local->remote-full-sync local->remote resume pause]}
+      (let [{:keys [remote->local remote->local-full-sync local->remote-full-sync local->remote resume pause stop]}
             (async/alt!
-             private-stop-sync-chan {:stop true}
              private-remote->local-full-sync-chan {:remote->local-full-sync true}
              private-remote->local-sync-chan {:remote->local true}
              private-full-sync-chan {:local->remote-full-sync true}
              private-pause-resume-chan ([v] (if v {:resume true} {:pause true}))
              remote-change-chan ([v] (println "remote change:" v) {:remote->local v})
              ratelimit-local-changes-chan ([v]
-                                           (let [rest-v (util/drain-chan ratelimit-local-changes-chan)
-                                                 vs     (cons v rest-v)]
-                                             (println "local changes:" vs)
-                                             {:local->remote vs}))
+                                           (if (nil? v)
+                                             {:stop true}
+                                             (let [rest-v (util/drain-chan ratelimit-local-changes-chan)
+                                                   vs     (cons v rest-v)]
+                                               (println "local changes:" vs)
+                                               {:local->remote vs})))
              (timeout (* 20 60 1000)) {:local->remote-full-sync true}
              :priority true)]
         (cond
           stop
-          (do (util/drain-chan ops-chan)
-              (>! ops-chan {:stop true}))
+          nil
+
           remote->local-full-sync
           (do (util/drain-chan ops-chan)
               (>! ops-chan {:remote->local-full-sync true})
@@ -2752,8 +2761,9 @@
                       :data  {:graph-uuid graph-uuid
                               :epoch      (tc/to-epoch (t/now))}})
     (go-loop []
-      (let [{:keys [resume]} (<! ops-chan)]
-        (if resume
+      (let [{:keys [resume] :as result} (<! ops-chan)]
+        (cond
+          resume
           (let [{:keys [remote->local remote->local-full-sync local->remote local->remote-full-sync] :as resume-state}
                 (get @*resume-state graph-uuid)]
             (resume-state--reset graph-uuid)
@@ -2775,6 +2785,11 @@
                                       :resume-state resume-state
                                       :epoch        (tc/to-epoch (t/now))}})
             (<! (.schedule this ::idle nil :resume)))
+
+          (nil? result)
+          (<! (.schedule this ::stop nil nil))
+
+          :else
           (recur)))))
 
   (idle [this]
@@ -2782,7 +2797,7 @@
       (let [{:keys [stop remote->local local->remote local->remote-full-sync remote->local-full-sync pause] :as result}
             (<! ops-chan)]
         (cond
-          stop
+          (or stop (nil? result))
           (<! (.schedule this ::stop nil nil))
           remote->local
           (<! (.schedule this ::remote->local {:remote remote->local} {:remote-changed remote->local}))
@@ -2796,9 +2811,11 @@
           (<! (.schedule this ::pause nil nil))
           :else
           (do
-            (state/pub-event! [:instrument {:type :sync/wrong-ops-chan-when-idle
-                                            :payload {:ops-chan-result result
-                                                      :state state}}])
+            (state/pub-event! [:capture-error {:error (js/Error. "sync/wrong-ops-chan-when-idle")
+                                               :payload {:type :sync/wrong-ops-chan-when-idle
+                                                         :ops-chan-result result
+                                                         :user-id user-uuid
+                                                         :graph-id graph-uuid}}])
             nil)))))
 
   (full-sync [this]
@@ -2828,10 +2845,11 @@
           (.schedule this ::stop nil nil)
           unknown
           (do
-            (state/pub-event! [:instrument {:type :sync/unknown
-                                            :event :local->remote-full-sync-failed
-                                            :graph-uuid graph-uuid
-                                            :payload {:error unknown}}])
+            (state/pub-event! [:capture-error {:error unknown
+                                               :payload {:type :sync/unknown
+                                                         :event :local->remote-full-sync-failed
+                                                         :user-id user-uuid
+                                                         :graph-uuid graph-uuid}}])
             (put-sync-event! {:event :local->remote-full-sync-failed
                               :data  {:graph-uuid graph-uuid
                                       :epoch      (tc/to-epoch (t/now))}})
@@ -2855,17 +2873,18 @@
               (.schedule this ::pause nil nil))
           unknown
           (do
-            (state/pub-event! [:instrument {:type :sync/unknown
-                                            :event :remote->local-full-sync-failed
-                                            :graph-uuid graph-uuid
-                                            :payload {:error unknown}}])
+            (state/pub-event! [:capture-error {:error unknown
+                                               :payload {:event :remote->local-full-sync-failed
+                                                         :type :sync/unknown
+                                                         :graph-uuid graph-uuid
+                                                         :user-id user-uuid}}])
             (put-sync-event! {:event :remote->local-full-sync-failed
                               :data  {:graph-uuid graph-uuid
                                       :exp        unknown
                                       :epoch      (tc/to-epoch (t/now))}})
             (let [next-state (if (string/includes? (str (ex-cause unknown)) "404 Not Found")
                                ;; TODO: this should never happen
-                               ::pause
+                               ::stop
                                ;; if any other exception occurred, re-exec remote->local-full-sync
                                ::remote->local-full-sync)]
               (.schedule this next-state nil nil)))))))
@@ -2899,10 +2918,11 @@
                 (.schedule this ::pause nil nil))
             unknown
             (do (prn "remote->local err" unknown)
-                (state/pub-event! [:instrument {:type :sync/unknown
-                                                :event :remote->local
-                                                :graph-uuid graph-uuid
-                                                :payload {:error unknown}}])
+                (state/pub-event! [:capture-error {:error unknown
+                                                   :payload {:type :sync/unknown
+                                                             :event :remote->local
+                                                             :user-id user-uuid
+                                                             :graph-uuid graph-uuid}}])
                 (.schedule this ::idle nil nil)))))))
 
   (local->remote [this {local-changes :local}]
@@ -2962,10 +2982,11 @@
           unknown
           (do
             (debug/pprint "local->remote" unknown)
-            (state/pub-event! [:instrument {:type :sync/unknown
-                                            :event :local->remote
-                                            :graph-uuid graph-uuid
-                                            :payload {:error unknown}}])
+            (state/pub-event! [:capture-error {:error unknown
+                                               :payload {:event :local->remote
+                                                         :type :sync/unknown
+                                                         :user-id user-uuid
+                                                         :graph-uuid graph-uuid}}])
             (.schedule this ::idle nil nil))))))
   IStoppable
   (-stop! [_]
@@ -2973,9 +2994,7 @@
       (when-not @*stopped?
         (vreset! *stopped? true)
         (ws-stop! *ws)
-        (offer! private-stop-sync-chan true)
         (async/untap full-sync-mult private-full-sync-chan)
-        (async/untap stop-sync-mult private-stop-sync-chan)
         (async/untap remote->local-sync-mult private-remote->local-sync-chan)
         (async/untap remote->local-full-sync-mult private-remote->local-full-sync-chan)
         (async/untap pause-resume-mult private-pause-resume-chan)
@@ -2983,14 +3002,9 @@
         (stop-local->remote! local->remote-syncer)
         (stop-remote->local! remote->local-syncer)
         (<! (<rsapi-cancel-all-requests))
-        (debug/pprint ["stop sync-manager, graph-uuid" graph-uuid "base-path" base-path])
         (swap! *sync-state sync-state--update-state ::stop)
-        (loop []
-          (if (not= ::stop state)
-            (do
-              (<! (timeout 100))
-              (recur))
-            (reset! current-sm-graph-uuid nil))))))
+        (reset! current-sm-graph-uuid nil)
+        (debug/pprint ["stop sync-manager, graph-uuid" graph-uuid "base-path" base-path]))))
 
   IStopped?
   (-stopped? [_]
@@ -3015,8 +3029,8 @@
     (.set-remote->local-syncer! local->remote-syncer remote->local-syncer)
     (.set-local->remote-syncer! remote->local-syncer local->remote-syncer)
     (swap! *sync-state sync-state--update-current-syncing-graph-uuid graph-uuid)
-    (->SyncManager graph-uuid base-path *sync-state local->remote-syncer remote->local-syncer remoteapi-with-stop
-                   nil *txid nil nil nil *stopped? *paused? nil (chan 1) (chan 1) (chan 1) (chan 1) (chan 1))))
+    (->SyncManager user-uuid graph-uuid base-path *sync-state local->remote-syncer remote->local-syncer remoteapi-with-stop
+                   nil *txid nil nil nil *stopped? *paused? nil (chan 1) (chan 1) (chan 1) (chan 1))))
 
 (defn sync-manager-singleton
   [user-uuid graph-uuid base-path repo txid *sync-state]

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

@@ -73,11 +73,7 @@
 (defn- instrument!
   []
   (let [total (srs/get-srs-cards-total)]
-    (state/set-state! :srs/cards-due-count total)
-    (state/pub-event! [:instrument {:type :flashcards/count
-                                    :payload {:total (or total 0)}}])
-    (state/pub-event! [:instrument {:type :blocks/count
-                                    :payload {:total (db/blocks-count)}}])))
+    (state/set-state! :srs/cards-due-count total)))
 
 (defn restore-and-setup!
   [repos]

+ 22 - 11
src/main/frontend/handler/conversion.cljs

@@ -15,10 +15,10 @@
   (set-config! repo :file/name-format format))
 
 (defn- calc-current-name
-  "If the file body is parsed as the same page name, but the page name has a 
-   different file sanitization result under the current sanitization form, return 
+  "If the file body is parsed as the same page name, but the page name has a
+   different file sanitization result under the current sanitization form, return
    the new file name.
-   Return: 
+   Return:
      the file name for the page name under the current file naming rules, or `nil`
      if no change of path happens"
   [format file-body prop-title]
@@ -33,7 +33,7 @@
 
 (defn- calc-previous-name
   "We want to recover user's title back under new file name sanity rules.
-   Return: 
+   Return:
      the file name for that page name under the current file naming rules,
      and the new title if no action applied, or `nil` if no break change happens"
   [old-format new-format file-body]
@@ -59,8 +59,6 @@
 ;;   - the special rule in `is-manual-title-prop?`
 (defonce supported-filename-formats [:triple-lowbar :legacy])
 
-;; In case of recovering this check in future
-#_:clj-kondo/ignore
 (defn- is-manual-title-prop?
   "If it's an user defined title property instead of the generated one"
   [format file-body prop-title]
@@ -74,7 +72,7 @@
   [old-format new-format file-body prop-title]
   ;; dont rename journal page. officially it's stored as `yyyy_mm_dd`
   ;; If it's a journal file imported with custom :journal/page-title-format,
-  ;;   and it includes reserved characters, format config change / file renaming is required. 
+  ;;   and it includes reserved characters, format config change / file renaming is required.
   ;;   It's about user's own data management decision and should be handled
   ;;   by user manually.
   ;; the 'expected' title of the user when updating from the previous format, or title will be broken in new format
@@ -90,7 +88,7 @@
       ret)))
 
 (defn calc-rename-target
-  "Return the renaming status and new file body to recover the original title of the file in previous version. 
+  "Return the renaming status and new file body to recover the original title of the file in previous version.
    The return title should be the same as the title in the index file in the previous version.
    return nil if no rename is needed.
    page: the page entity
@@ -98,12 +96,25 @@
    old-format, new-format: the filename formats
    Return:
      {:status        :informal | :breaking | :unreachable
+      :file-name original file name
       :target        the new file name
       :old-title     the old title
       :changed-title the new title} | nil"
   [page path old-format new-format]
   (let [prop-title (get-in page [:block/properties :title])
         file-body  (gp-util/path->file-body path)
-        journal?   (:block/journal? page)]
-    (when (not journal?)
-      (calc-rename-target-impl old-format new-format file-body prop-title))))
+        journal?   (:block/journal? page)
+        manual-prop-title? (is-manual-title-prop? old-format file-body prop-title)]
+    (cond
+      (and (not journal?)
+           (not manual-prop-title?))
+      (calc-rename-target-impl old-format new-format file-body prop-title)
+
+      (and (not journal?)
+           manual-prop-title?
+           (fs-util/include-reserved-chars? file-body))
+      {:status        :informal
+       :file-name     file-body
+       :target        (fs-util/file-name-sanity file-body new-format)
+       :old-title     prop-title
+       :changed-title prop-title})))

+ 5 - 27
src/main/frontend/handler/editor.cljs

@@ -17,13 +17,11 @@
             [frontend.handler.block :as block-handler]
             [frontend.handler.common :as common-handler]
             [frontend.handler.export :as export]
-            [frontend.handler.image :as image-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.repeated :as repeated]
             [frontend.handler.route :as route-handler]
             [frontend.handler.assets :as assets-handler]
             [frontend.idb :as idb]
-            [frontend.image :as image]
             [frontend.mobile.util :as mobile-util]
             [frontend.modules.outliner.core :as outliner-core]
             [frontend.modules.outliner.transaction :as outliner-tx]
@@ -1322,9 +1320,10 @@
 
 (defn get-asset-file-link
   [format url file-name image?]
-  (let [pdf? (and url (string/ends-with? (string/lower-case url) ".pdf"))]
+  (let [pdf? (and url (string/ends-with? (string/lower-case url) ".pdf"))
+        video? (and url (util/ext-of-video? url))]
     (case (keyword format)
-      :markdown (util/format (str (when (or image? pdf?) "!") "[%s](%s)") file-name url)
+      :markdown (util/format (str (when (or image? video? pdf?) "!") "[%s](%s)") file-name url)
       :org (if image?
              (util/format "[[%s]]" url)
              (util/format "[[%s][%s]]" url file-name))
@@ -1464,7 +1463,7 @@
   [id ^js files format uploading? drop-or-paste?]
   (let [repo (state/get-current-repo)
         block (state/get-edit-block)]
-    (if (config/local-db? repo)
+    (when (config/local-db? repo)
       (-> (save-assets! block repo (js->clj files))
           (p/then
            (fn [res]
@@ -1487,28 +1486,7 @@
             (fn []
               (reset! uploading? false)
               (reset! *asset-uploading? false)
-              (reset! *asset-uploading-process 0))))
-      (image/upload
-       files
-       (fn [file file-name file-type]
-         (image-handler/request-presigned-url
-          file file-name file-type
-          uploading?
-          (fn [signed-url]
-            (insert-command! id
-                             (get-asset-file-link format signed-url file-name true)
-                             format
-                             {:last-pattern (if drop-or-paste? "" (state/get-editor-command-trigger))
-                              :restore?     true})
-
-            (reset! *asset-uploading? false)
-            (reset! *asset-uploading-process 0))
-          (fn [e]
-            (let [process (* (/ (gobj/get e "loaded")
-                                (gobj/get e "total"))
-                             100)]
-              (reset! *asset-uploading? false)
-              (reset! *asset-uploading-process process)))))))))
+              (reset! *asset-uploading-process 0)))))))
 
 ;; Editor should track some useful information, like editor modes.
 ;; For example:

+ 19 - 9
src/main/frontend/handler/events.cljs

@@ -59,7 +59,9 @@
             [logseq.db.schema :as db-schema]
             [promesa.core :as p]
             [rum.core :as rum]
-            [logseq.graph-parser.config :as gp-config]))
+            [logseq.graph-parser.config :as gp-config]
+            [cljs-bean.core :as bean]
+            ["@sentry/react" :as Sentry]))
 
 ;; TODO: should we move all events here?
 
@@ -362,7 +364,7 @@
   (repo-handler/graph-ready! repo)
   (when (and (util/electron?)
              (not (config/demo-graph?))
-             (= :legacy (state/get-filename-format)))
+             (= :legacy (state/get-filename-format repo)))
     (state/pub-event! [:ui/notify-outdated-filename-format []])))
 
 (defmethod handle :notification/show [[_ {:keys [content status clear?]}]]
@@ -403,9 +405,15 @@
 (defmethod handle :redirect-to-home [_]
   (page-handler/create-today-journal!))
 
-(defmethod handle :instrument [[_ {:keys [type payload]}]]
+(defmethod handle :instrument [[_ {:keys [type payload] :as opts}]]
+  (when-not (empty? (dissoc opts :type :payload))
+    (js/console.error "instrument data-map should only contains [:type :payload]"))
   (posthog/capture type payload))
 
+(defmethod handle :capture-error [[_ {:keys [error payload]}]]
+  (Sentry/captureException error
+                           (bean/->js {:extra payload})))
+
 (defmethod handle :exec-plugin-cmd [[_ {:keys [pid cmd action]}]]
   (commands/exec-plugin-simple-command! pid cmd action))
 
@@ -452,7 +460,9 @@
       (when-let [left-sidebar-node (gdom/getElement "left-sidebar")]
         (set! (.. left-sidebar-node -style -bottom) "0px"))
       (when-let [right-sidebar-node (gdom/getElementByClass "sidebar-item-list")]
-        (set! (.. right-sidebar-node -style -paddingBottom) "150px")))))
+        (set! (.. right-sidebar-node -style -paddingBottom) "150px"))
+      (when-let [toolbar (.querySelector main-node "#mobile-editor-toolbar")]
+        (set! (.. toolbar -style -bottom) 0)))))
 
 (defn update-file-path [deprecated-repo current-repo deprecated-app-id current-app-id]
   (let [files (db-model/get-files-entity deprecated-repo)
@@ -858,8 +868,8 @@
 
                              :else
                              (do
-                               (state/pub-event! [:instrument {:type :file/parse-and-load-error
-                                                               :payload error}])
+                               (state/pub-event! [:capture-error {:error error
+                                                                  :payload {:type :file/parse-and-load-error}}])
                                [:li.my-1 {:key file}
                                 [:a {:on-click #(js/window.apis.openPath file)} file]
                                 [:p (.-message error)]]))))]
@@ -876,9 +886,9 @@
           (catch :default error
             (let [type :handle-system-events/failed]
               (js/console.error (str type) (clj->js payload) "\n" error)
-              (state/pub-event! [:instrument {:type    type
-                                              :payload payload
-                                              :error error}])))))
+              (state/pub-event! [:capture-error {:error error
+                                                 :payload {:type type
+                                                           :payload payload}}])))))
       (recur))
     chan))
 

+ 6 - 10
src/main/frontend/handler/file.cljs

@@ -149,11 +149,9 @@
 
                      (println "Write file failed, path: " path ", content: " content)
                      (log/error :write/failed error)
-                     (state/pub-event! [:instrument {:type :write-file/failed-for-alter-file
-                                                     :payload {:path path
-                                                               :content-length (count content)
-                                                               :error-str (str error)
-                                                               :error error}}])))
+                     (state/pub-event! [:capture-error
+                                        {:error error
+                                         :payload {:type :write-file/failed-for-alter-file}}])))
     result))
 
 (defn set-file-content!
@@ -178,11 +176,9 @@
                                                                            (str error))
                                                              :status :error
                                                              :clear? false}])
-                                         (state/pub-event! [:instrument {:type :write-file/failed
-                                                                         :payload {:path path
-                                                                                   :content-length (count content)
-                                                                                   :error-str (str error)
-                                                                                   :error error}}])
+                                         (state/pub-event! [:capture-error
+                                                            {:error error
+                                                             :payload {:type :write-file/failed}}])
                                          (log/error :write-file/failed {:path path
                                                                         :content content
                                                                         :error error})))))))

+ 0 - 44
src/main/frontend/handler/image.cljs

@@ -2,7 +2,6 @@
   (:require [clojure.string :as string]
             [frontend.config :as config]
             [frontend.fs :as fs]
-            [frontend.handler.notification :as notification]
             [frontend.image :as image]
             [frontend.state :as state]
             [frontend.util :as util]
@@ -51,46 +50,3 @@
                (js/console.dir error))))))
       (catch :default _e
         nil))))
-
-(defn request-presigned-url
-  [file filename mime-type uploading? url-handler on-processing]
-  (cond
-    (> (gobj/get file "size") (* 12 1024 1024))
-    (notification/show! [:p "Sorry, we don't support any file that's larger than 12MB."] :error)
-
-    :else
-    (do
-      (reset! uploading? true)
-      ;; start uploading?
-      (util/post (str config/api "presigned_url")
-                 {:filename filename
-                  :mime-type mime-type}
-                 (fn [{:keys [presigned-url s3-object-key] :as resp}]
-                   (if presigned-url
-                     (util/upload presigned-url
-                                  file
-                                  (fn [_result]
-                                    ;; request cdn signed url
-                                    (util/post (str config/api "signed_url")
-                                               {:s3-object-key s3-object-key}
-                                               (fn [{:keys [signed-url]}]
-                                                 (reset! uploading? false)
-                                                 (if signed-url
-                                                   (url-handler signed-url)
-                                                   (prn "Something error, can't get a valid signed url.")))
-                                               (fn [_error]
-                                                 (reset! uploading? false)
-                                                 (prn "Something error, can't get a valid signed url."))))
-                                  (fn [error]
-                                    (reset! uploading? false)
-                                    (prn "upload failed.")
-                                    (js/console.dir error))
-                                  (fn [e]
-                                    (on-processing e)))
-                     ;; TODO: notification, or re-try
-                     (do
-                       (reset! uploading? false)
-                       (prn "failed to get any presigned url, resp: " resp))))
-                 (fn [_error]
-                   ;; (prn "Get token failed, error: " error)
-                   (reset! uploading? false))))))

+ 6 - 4
src/main/frontend/handler/repo.cljs

@@ -217,7 +217,9 @@
                           (assoc opts' :skip-db-transact? false)
                           opts')
                   result (parse-and-load-file! repo-url file opts')
-                  page-name (some (fn [x] (and (map? x) (:block/name x))) result)
+                  page-name (some (fn [x] (when (and (map? x) (:block/original-name x )
+                                                     (= (:file/path file) (:file/path (:block/file x))))
+                                            (:block/name x))) result)
                   page-exists? (and page-name (get @*page-names page-name))
                   tx' (cond
                         whiteboard? tx
@@ -422,9 +424,9 @@
        (on-success)))
     (p/catch (fn [error]
                (js/console.error error)
-               (state/pub-event! [:instrument {:type :db/persist-failed
-                                               :payload {:error-str (str error)
-                                                         :error error}}])
+               (state/pub-event! [:capture-error
+                                  {:error error
+                                   :payload {:type :db/persist-failed}}])
                (when on-error
                  (on-error)))))))
 

+ 0 - 18
src/main/frontend/image.cljs

@@ -1,8 +1,6 @@
 (ns frontend.image
   "Image related utility fns"
   (:require ["/frontend/exif" :as exif]
-            [clojure.string :as string]
-            [frontend.date :as date]
             [goog.object :as gobj]))
 
 (defn reverse?
@@ -70,19 +68,3 @@
   (.createObjectURL (or (.-URL js/window)
                         (.-webkitURL js/window))
                     file))
-
-;; (defn build-image
-;;   []
-;;   (let [img (js/Image.)]
-;;     ))
-
-(defn upload
-  [files file-handler & {:keys [files-limit]
-                         :or {files-limit 1}}]
-  (doseq [file (take files-limit (array-seq files))]
-    (let [file-type (gobj/get file "type")
-          ymd (->> (vals (date/year-month-day-padded))
-                   (string/join "_"))
-          file-name (str ymd "_" (gobj/get file "name"))]
-      (when (= 0 (.indexOf file-type "image/"))
-        (file-handler file file-name file-type)))))

+ 8 - 7
src/main/frontend/mobile/camera.cljs

@@ -23,13 +23,14 @@
                       (log/error :photo/get-failed {:error error})))
           filename (str (date/get-date-time-string-2) ".jpeg")
           path (editor-handler/get-asset-path filename)
-          _file (p/catch
-                    (.writeFile Filesystem (clj->js {:data (.-base64String photo)
-                                                     :path path
-                                                     :recursive true}))
-                    (fn [error]
-                      (log/error :file/write-failed {:path path
-                                                     :error error})))]
+          _file (when photo
+                  (p/catch
+                     (.writeFile Filesystem (clj->js {:data (.-base64String photo)
+                                                      :path path
+                                                      :recursive true}))
+                     (fn [error]
+                       (log/error :file/write-failed {:path path
+                                                      :error error}))))]
     (p/resolved filename)))
 
 (defn embed-photo [id]

+ 2 - 4
src/main/frontend/modules/instrumentation/sentry.cljs

@@ -3,8 +3,6 @@
             [frontend.util :as util]
             [frontend.config :as config]
             ["@sentry/react" :as Sentry]
-            ["@sentry/tracing" :refer [BrowserTracing]]
-            ["posthog-js" :as posthog]
             [frontend.mobile.util :as mobile-util]))
 
 (def config
@@ -21,8 +19,8 @@
                                (mobile-util/native-platform?) "mobile"
                                :else "web")
                    :publishing config/publishing?}}
-   :integrations [(new posthog/SentryIntegration posthog "logseq" 5311485)
-                  (new BrowserTracing)]
+   ;; :integrations [(new posthog/SentryIntegration posthog "logseq" 5311485)
+   ;;                (new BrowserTracing)]
    :debug config/dev?
    :tracesSampleRate 1.0
    :beforeSend (fn [^js event]

+ 6 - 5
src/main/frontend/modules/outliner/core.cljs

@@ -511,11 +511,12 @@
         tx (insert-blocks-aux blocks' target-block' insert-opts)]
     (if (some (fn [b] (or (nil? (:block/parent b)) (nil? (:block/left b)))) tx)
       (do
-        (state/pub-event! [:instrument {:type :outliner/invalid-structure
-                                        :payload {:blocks blocks
-                                                  :target-block target-block'
-                                                  :opt opts
-                                                  :data (mapv #(dissoc % :block/content) tx)}}])
+        (state/pub-event! [:capture-error {:error "Outliner invalid structure"
+                                           :payload {:type :outliner/invalid-structure
+                                                     :blocks blocks
+                                                     :target-block target-block'
+                                                     :opt opts
+                                                     :data (mapv #(dissoc % :block/content) tx)}}])
         (throw (ex-info "Invalid outliner data"
                         {:opts insert-opts
                          :tx (vec tx)

+ 2 - 5
src/main/frontend/state.cljs

@@ -69,7 +69,7 @@
 
      ;; ui
      :ui/viewport                           {}
-     
+
      ;; left sidebar
      :ui/navigation-item-collapsed?         {}
 
@@ -307,10 +307,7 @@
 (def default-config
   "Default config for a repo-specific, user config"
   {:feature/enable-search-remove-accents? true
-   :default-arweave-gateway "https://arweave.net"
-
-   ;; For flushing the settings of old versions. Don't bump this value.
-   :file/name-format :legacy})
+   :default-arweave-gateway "https://arweave.net"})
 
 ;; State that most user config is dependent on
 (declare get-current-repo sub set-state!)

+ 3 - 3
src/main/frontend/ui.cljs

@@ -56,13 +56,13 @@
 (defonce icon-size (if (mobile-util/native-platform?) 26 20))
 
 (def block-background-colors
-  ["gray"
+  ["yellow"
    "red"
-   "yellow"
+   "pink"
    "green"
    "blue"
    "purple"
-   "pink"])
+   "gray"])
 
 (rum/defc ls-textarea
   < rum/reactive

+ 7 - 24
src/main/frontend/util.cljc

@@ -11,6 +11,7 @@
             ["remove-accents" :as removeAccents]
             ["sanitize-filename" :as sanitizeFilename]
             ["check-password-strength" :refer [passwordStrength]]
+            ["path-complete-extname" :as pathCompleteExtname]
             [frontend.loader :refer [load]]
             [cljs-bean.core :as bean]
             [cljs-time.coerce :as tc]
@@ -43,7 +44,7 @@
        (-write writer (str "\"" (.toString sym) "\"")))))
 
 #?(:cljs (defonce ^js node-path utils/nodePath))
-#?(:cljs (defonce ^js full-path-extname utils/fullPathExtname))
+#?(:cljs (defonce ^js full-path-extname pathCompleteExtname))
 #?(:cljs (defn app-scroll-container-node
            ([]
             (gdom/getElement "main-content-container"))
@@ -200,6 +201,11 @@
              (string/ends-with? %))
         [".png" ".jpg" ".jpeg" ".bmp" ".gif" ".webp" ".svg"]))
 
+(defn ext-of-video? [s]
+  (some #(-> (string/lower-case s)
+             (string/ends-with? %))
+        [".mp4" ".mkv" ".mov" ".wmv" ".avi" ".webm" ".mpg" ".ts" ".ogg" ".flv"]))
+
 ;; ".lg:absolute.lg:inset-y-0.lg:right-0.lg:w-1/2"
 (defn hiccup->class
   [class]
@@ -222,29 +228,6 @@
                            (.then #(on-ok %)))
                        (on-failed resp)))))))))
 
-#?(:cljs
-   (defn upload
-     [url file on-ok on-failed on-progress]
-     (let [xhr (js/XMLHttpRequest.)]
-       (.open xhr "put" url)
-       (gobj/set xhr "onload" on-ok)
-       (gobj/set xhr "onerror" on-failed)
-       (when (and (gobj/get xhr "upload")
-                  on-progress)
-         (gobj/set (gobj/get xhr "upload")
-                   "onprogress"
-                   on-progress))
-       (.send xhr file))))
-
-#?(:cljs
-   (defn post
-     [url body on-ok on-failed]
-     (fetch url {:method "post"
-                 :headers {:Content-Type "application/json"}
-                 :body (js/JSON.stringify (clj->js body))}
-            on-ok
-            on-failed)))
-
 (defn zero-pad
   [n]
   (if (< n 10)

+ 1 - 1
src/test/frontend/db/name_sanity_test.cljs

@@ -74,7 +74,7 @@
     "aaa__bbb__cccon" "aaa/bbb/cccon"  true
     "aaa.bbb.ccc"     "adbcde/aks/sdf" true
     "a__.bbb.ccc"     "adbcde/aks/sdf" true
-    ))
+    "aaa__bbb__ccc" nil false))
 
 (deftest rename-previous-tests
   (are [x y] (= y (#'conversion-handler/calc-previous-name :legacy :triple-lowbar x))

+ 5 - 5
templates/config.edn

@@ -254,7 +254,7 @@
  ;; ignore #+keyword: for parsing page references in orgmode
  ;; :ignored-page-references-keywords #{"author" "startup"}
 
- ;; Quick capture templates on mobile for recieving contents from other apps.
+ ;; Quick capture templates for recieving contents from other apps.
  ;; Each template contains three elements {time}, {text} and {url}, which can be auto-expanded
  ;; by received contents from other apps. Note: the {} cannot be omitted.
  ;; - {time}: capture time
@@ -266,6 +266,9 @@
  ;; {:text "[[quick capture]] **{time}**: {text} from {url}"
  ;;  :media "[[quick capture]] **{time}**: {url}"}
 
+ ;; Quick capture options
+ ;; :quick-capture-options {:insert-today? false :redirect-page? false}
+
  ;; File sync options
  ;; Ignore these files when syncing, regexp is supported.
  ;; :file-sync/ignore-files []
@@ -284,7 +287,7 @@
  ;; Decide the way to escape the special characters in the page title.
  ;; Warning:
  ;;   This is a dangerous operation. If you want to change the setting,
- ;;   should access the setting `Filename format` and follow the instructions. 
+ ;;   should access the setting `Filename format` and follow the instructions.
  ;;   Or you have to rename all the affected files manually then re-index on all
  ;;   clients after the files are synced. Wrong handling may cause page titles
  ;;   containing special characters to be messy.
@@ -292,8 +295,5 @@
  ;;   :file/name-format :triple-lowbar
  ;;     ;use triple underscore `___` for slash `/` in page title
  ;;     ;use Percent-encoding for other invalid characters
- ;;   :file/name-format :legacy
- ;;     ;use Percent-encoding for slash and other invalid characters
- ;;     ;parse `.` in file name as slash `/` in page title
  :file/name-format :triple-lowbar
  }

+ 1 - 1
tldraw/README.md

@@ -8,7 +8,7 @@ This folder contains the JS codes for a custom build of Tldraw to fit the needs
 
 ### Prerequisites
 
-Morden JS eco tools like Node.js and yarn.
+Modern JS eco tools like Node.js and yarn.
 
 ### Run in dev mode
 

+ 1 - 1
tldraw/apps/tldraw-logseq/src/lib/shapes/LineShape.tsx

@@ -161,7 +161,7 @@ export class LineShape extends TLLineShape<LineShapeProps> {
       <>
         <Arrow
           style={{
-            stroke: getComputedColor(stroke, 'stroke'),
+            stroke: getComputedColor(stroke, 'text'),
             fill,
             strokeWidth,
             strokeType,

+ 2 - 2
tldraw/apps/tldraw-logseq/src/lib/shapes/PencilShape.tsx

@@ -131,8 +131,8 @@ export class PencilShape extends TLDrawShape<PencilShapeProps> {
         strokeWidth={strokeWidth / 2}
         strokeLinejoin="round"
         strokeLinecap="round"
-        stroke={getComputedColor(stroke, 'stroke')}
-        fill={getComputedColor(stroke, 'stroke')}
+        stroke={getComputedColor(stroke, 'text')}
+        fill={getComputedColor(stroke, 'text')}
         strokeDasharray={strokeType === 'dashed' ? '12 4' : undefined}
       />
     )

+ 1 - 1
tldraw/apps/tldraw-logseq/src/styles.css

@@ -7,7 +7,7 @@
   --ls-wb-stroke-color-purple: var(--color-purple-500, purple);
   --ls-wb-stroke-color-pink: var(--color-pink-500, pink);
   --ls-wb-stroke-color-default: var(--ls-secondary-border-color);
-  --ls-wb-text-color-default: var(--ls-secondary-text-color);
+  --ls-wb-text-color-default: var(--ls-primary-text-color);
   --ls-wb-background-color-default: var(--ls-tertiary-background-color);
 }
 

+ 3 - 3
tldraw/packages/core/src/types/types.ts

@@ -4,13 +4,13 @@ import type { TLEventMap } from './TLEventMap'
 import type { TLHandle } from './TLHandle'
 
 export enum Color {
-  Gray = 'gray',
-  Red = 'red',
   Yellow = 'yellow',
+  Red = 'red',
+  Pink = 'pink',
   Green = 'green',
   Blue = 'blue',
   Purple = 'purple',
-  Pink = 'pink',
+  Gray = 'gray',
   Default = '',
 }
 

+ 0 - 5
yarn.lock

@@ -487,11 +487,6 @@
     "@jridgewell/resolve-uri" "^3.0.3"
     "@jridgewell/sourcemap-codec" "^1.4.10"
 
-"@kanru/rage-wasm@^0.3.0":
-  version "0.3.0"
-  resolved "https://registry.yarnpkg.com/@kanru/rage-wasm/-/rage-wasm-0.3.0.tgz#de96b1fda1f781ff401d43b50d0f95b7338c4399"
-  integrity sha512-2LMRS27nNJPqFNpRQL7kXG0kgBeIPo63KM6u0Xu6Es5XIS7LP4MFtdHkCg8Pt7IhMM7GuOa2YnzAZgKBxE1lcw==
-
 "@logseq/[email protected]":
   version "0.0.14"
   resolved "https://registry.yarnpkg.com/@logseq/capacitor-file-sync/-/capacitor-file-sync-0.0.14.tgz#f358f42e95e0578c2853477a66491c8f221a7c15"