Răsfoiți Sursa

Merge branch 'master' into dev/malli-schema&kondo-config

Gabriel Horner 3 ani în urmă
părinte
comite
d1157b0181

+ 11 - 4
docs/dev-practices.md

@@ -77,10 +77,13 @@ mistakes [as noted here](./contributing-to-translations.md#fix-mistakes).
 
 
 ## Testing
 ## Testing
 
 
+Even though we have a nightly release channel, it's hard for testing users (thanks to the brave users!) to notice all issues in a limited time, as Logseq is covering so many features (and the hell of combinations) 
+The only solution is automatic end-to-end tests - adding tests for GUI software is always painful but necessary
 We have unit and end to end tests.
 We have unit and end to end tests.
 
 
 ### End to End Tests
 ### End to End Tests
 
 
+https://github.com/logseq/logseq/pulls?q=E2E 
 To run end to end tests
 To run end to end tests
 
 
 ```sh
 ```sh
@@ -95,11 +98,15 @@ If e2e failed after first running:
 - `rm -rdf <repo dir>/tmp/`  
 - `rm -rdf <repo dir>/tmp/`  
 - Windows: `rmdir /s %APPDATA%/Electron`  (Reference: https://www.electronjs.org/de/docs/latest/api/app#appgetpathname)
 - Windows: `rmdir /s %APPDATA%/Electron`  (Reference: https://www.electronjs.org/de/docs/latest/api/app#appgetpathname)
 
 
-If e2e tests fail, they can be debugged by examining a trace dump with [the
+There's a `traceAll()` helper function to enable playwright trace file dump for specific test files https://github.com/logseq/logseq/pull/8332
+
+If e2e tests fail in the file, they can be debugged by examining a trace dump with [the
 playwright trace
 playwright trace
-viewer](https://playwright.dev/docs/trace-viewer#recording-a-trace). Locally
-this will get dumped into e2e-dump/. On CI the trace file will be under
-Artifacts at the bottom of a run page e.g.
+viewer](https://playwright.dev/docs/trace-viewer#recording-a-trace). 
+
+Locally this will get dumped into e2e-dump/. 
+
+On CI the trace file will be under Artifacts at the bottom of a run page e.g.
 https://github.com/logseq/logseq/actions/runs/3574600322.
 https://github.com/logseq/logseq/actions/runs/3574600322.
 
 
 ### Unit Testing
 ### Unit Testing

+ 87 - 0
e2e-tests/editor.spec.ts

@@ -596,3 +596,90 @@ test('should not erase typed text when expanding block quickly after typing #389
     ''
     ''
   )
   )
 })
 })
+
+test('should keep correct undo and redo seq after indenting or outdenting the block #7615',async({page,block}) => {
+  await createRandomPage(page)
+
+  await block.mustFill("foo")
+  
+  await page.keyboard.press("Enter")
+  await expect(page.locator('textarea >> nth=0')).toHaveText("")
+  await block.indent()
+  await block.mustFill("bar")
+  await expect(page.locator('textarea >> nth=0')).toHaveText("bar")
+
+  if (IsMac) {
+    await page.keyboard.press('Meta+z')
+  } else {
+    await page.keyboard.press('Control+z')
+  }
+  // should undo "bar" input
+  await expect(page.locator('textarea >> nth=0')).toHaveText("")
+  if (IsMac) {
+    await page.keyboard.press('Shift+Meta+z')
+  } else {
+    await page.keyboard.press('Shift+Control+z')
+  }
+  // should redo "bar" input
+  await expect(page.locator('textarea >> nth=0')).toHaveText("bar")
+  await page.keyboard.press("Shift+Tab")
+  
+  await page.keyboard.press("Enter")
+  await expect(page.locator('textarea >> nth=0')).toHaveText("")
+  // swap input seq
+  await block.mustFill("baz")
+  await block.indent()
+
+  if (IsMac) {
+    await page.keyboard.press('Meta+z')
+  } else {
+    await page.keyboard.press('Control+z')
+  }
+  // should undo indention
+  await expect(page.locator('textarea >> nth=0')).toHaveText("baz")
+  await page.keyboard.press("Shift+Tab")
+
+  await page.keyboard.press("Enter")
+  await expect(page.locator('textarea >> nth=0')).toHaveText("")
+  // #7615
+  await page.keyboard.type("aaa")
+  await block.indent()
+  await page.keyboard.type(" bbb")
+  await expect(page.locator('textarea >> nth=0')).toHaveText("aaa bbb")
+  if (IsMac) {
+    await page.keyboard.press('Meta+z')
+  } else {
+    await page.keyboard.press('Control+z')
+  }
+  await expect(page.locator('textarea >> nth=0')).toHaveText("aaa")
+  if (IsMac) {
+    await page.keyboard.press('Meta+z')
+  } else {
+    await page.keyboard.press('Control+z')
+  }
+  await expect(page.locator('textarea >> nth=0')).toHaveText("aaa")
+  if (IsMac) {
+    await page.keyboard.press('Meta+z')
+  } else {
+    await page.keyboard.press('Control+z')
+  }
+  await expect(page.locator('textarea >> nth=0')).toHaveText("")
+  if (IsMac) {
+    await page.keyboard.press('Shift+Meta+z')
+  } else {
+    await page.keyboard.press('Shift+Control+z')
+  }
+  await expect(page.locator('textarea >> nth=0')).toHaveText("aaa")
+  if (IsMac) {
+    await page.keyboard.press('Shift+Meta+z')
+  } else {
+    await page.keyboard.press('Shift+Control+z')
+  }
+  await expect(page.locator('textarea >> nth=0')).toHaveText("aaa")
+  if (IsMac) {
+    await page.keyboard.press('Shift+Meta+z')
+  } else {
+    await page.keyboard.press('Shift+Control+z')
+  }
+  await expect(page.locator('textarea >> nth=0')).toHaveText("aaa bbb")
+})

+ 1 - 1
package.json

@@ -90,7 +90,7 @@
         "@capawesome/capacitor-background-task": "^2.0.0",
         "@capawesome/capacitor-background-task": "^2.0.0",
         "@excalidraw/excalidraw": "0.12.0",
         "@excalidraw/excalidraw": "0.12.0",
         "@hugotomazi/capacitor-navigation-bar": "^2.0.0",
         "@hugotomazi/capacitor-navigation-bar": "^2.0.0",
-        "@logseq/capacitor-file-sync": "0.0.17",
+        "@logseq/capacitor-file-sync": "0.0.18",
         "@logseq/react-tweet-embed": "1.3.1-1",
         "@logseq/react-tweet-embed": "1.3.1-1",
         "@sentry/react": "^6.18.2",
         "@sentry/react": "^6.18.2",
         "@sentry/tracing": "^6.18.2",
         "@sentry/tracing": "^6.18.2",

+ 1 - 1
resources/package.json

@@ -37,7 +37,7 @@
     "https-proxy-agent": "5.0.0",
     "https-proxy-agent": "5.0.0",
     "@sentry/electron": "2.5.1",
     "@sentry/electron": "2.5.1",
     "posthog-js": "1.10.2",
     "posthog-js": "1.10.2",
-    "@logseq/rsapi": "0.0.59",
+    "@logseq/rsapi": "0.0.60",
     "electron-deeplink": "1.0.10",
     "electron-deeplink": "1.0.10",
     "abort-controller": "3.0.0",
     "abort-controller": "3.0.0",
     "fastify": "latest",
     "fastify": "latest",

+ 45 - 23
src/electron/electron/handler.cljs

@@ -1,34 +1,34 @@
 (ns electron.handler
 (ns electron.handler
   "This ns starts the event handling for the electron main process and defines
   "This ns starts the event handling for the electron main process and defines
   all the application-specific event types"
   all the application-specific event types"
-  (:require ["electron" :refer [ipcMain dialog app autoUpdater shell]]
-            [cljs-bean.core :as bean]
-            ["fs" :as fs]
+  (:require ["/electron/utils" :as js-utils]
+            ["abort-controller" :as AbortController]
             ["buffer" :as buffer]
             ["buffer" :as buffer]
+            ["diff-match-patch" :as google-diff]
+            ["electron" :refer [app autoUpdater dialog ipcMain shell]]
+            ["fs" :as fs]
             ["fs-extra" :as fs-extra]
             ["fs-extra" :as fs-extra]
-            ["path" :as path]
             ["os" :as os]
             ["os" :as os]
-            ["diff-match-patch" :as google-diff]
-            ["/electron/utils" :as js-utils]
-            ["abort-controller" :as AbortController]
-            [electron.shell :as shell]
-            [electron.fs-watcher :as watcher]
-            [electron.configs :as cfgs]
-            [promesa.core :as p]
-            [clojure.string :as string]
-            [electron.utils :as utils]
-            [electron.logger :as logger]
-            [electron.state :as state]
+            ["path" :as path]
+            [cljs-bean.core :as bean]
+            [cljs.reader :as reader]
             [clojure.core.async :as async]
             [clojure.core.async :as async]
-            [electron.search :as search]
+            [clojure.string :as string]
+            [electron.backup-file :as backup-file]
+            [electron.configs :as cfgs]
+            [electron.file-sync-rsapi :as rsapi]
+            [electron.find-in-page :as find]
+            [electron.fs-watcher :as watcher]
             [electron.git :as git]
             [electron.git :as git]
+            [electron.logger :as logger]
             [electron.plugin :as plugin]
             [electron.plugin :as plugin]
-            [electron.window :as win]
-            [electron.file-sync-rsapi :as rsapi]
-            [electron.backup-file :as backup-file]
-            [cljs.reader :as reader]
+            [electron.search :as search]
             [electron.server :as server]
             [electron.server :as server]
-            [electron.find-in-page :as find]))
+            [electron.shell :as shell]
+            [electron.state :as state]
+            [electron.utils :as utils]
+            [electron.window :as win]
+            [promesa.core :as p]))
 
 
 (defmulti handle (fn [_window args] (keyword (first args))))
 (defmulti handle (fn [_window args] (keyword (first args))))
 
 
@@ -177,12 +177,34 @@
           result (get (js->clj result) "filePaths")]
           result (get (js->clj result) "filePaths")]
     (p/resolved (first result))))
     (p/resolved (first result))))
 
 
-(defmethod handle :openDir [^js _window _messages]
+(defn- pretty-print-js-error
+  "Converts file related JS Error messages to a human readable format.
+   Ex.:
+   Error: EACCES: permission denied, scandir '/tmp/test'
+   Permission denied for path: '/tmp/test' (Code: EACCES)"
+  [e]
+  (some->>
+   e
+   str
+   ;; Message parsed as "Error: $ERROR_CODE$: $REASON$, function $PATH$"
+   (re-matches #"(?:Error\: )(.+)(?:\: )(.+)(?:, \w+ )('.+')")
+   rest
+   (#(str (string/capitalize (second %)) " for path: " (nth % 2) " (Code: " (first %) ")"))))
+
+(defmethod handle :openDir [^js window _messages]
   (logger/info ::open-dir "open folder selection dialog")
   (logger/info ::open-dir "open folder selection dialog")
   (p/let [path (open-dir-dialog)]
   (p/let [path (open-dir-dialog)]
     (logger/debug ::open-dir {:path path})
     (logger/debug ::open-dir {:path path})
     (if path
     (if path
-      (p/resolved (bean/->js (get-files path)))
+      (try
+        (p/resolved (bean/->js (get-files path)))
+        (catch js/Error e 
+          (do
+            (utils/send-to-renderer window "notification" {:type "error"
+                                                           :payload (str "Opening the specified directory failed.\n"
+                                                                         (or (pretty-print-js-error e) (str "Unexpected error: " e)))})
+            (p/rejected e))))
+
       (p/rejected (js/Error "path empty")))))
       (p/rejected (js/Error "path empty")))))
 
 
 (defmethod handle :getFiles [_window [_ path]]
 (defmethod handle :getFiles [_window [_ path]]

+ 4 - 4
src/main/frontend/handler/editor.cljs

@@ -1660,11 +1660,11 @@
   [up?]
   [up?]
   (fn [event]
   (fn [event]
     (util/stop event)
     (util/stop event)
+    (save-current-block!)
     (let [edit-block-id (:block/uuid (state/get-edit-block))
     (let [edit-block-id (:block/uuid (state/get-edit-block))
           move-nodes (fn [blocks]
           move-nodes (fn [blocks]
                        (outliner-tx/transact!
                        (outliner-tx/transact!
                         {:outliner-op :move-blocks}
                         {:outliner-op :move-blocks}
-                        (save-current-block!)
                         (outliner-core/move-blocks-up-down! blocks up?))
                         (outliner-core/move-blocks-up-down! blocks up?))
                        (when-let [block-node (util/get-first-block-by-id (:block/uuid (first blocks)))]
                        (when-let [block-node (util/get-first-block-by-id (:block/uuid (first blocks)))]
                          (.scrollIntoView block-node #js {:behavior "smooth" :block "nearest"})))]
                          (.scrollIntoView block-node #js {:behavior "smooth" :block "nearest"})))]
@@ -2139,10 +2139,10 @@
   [node]
   [node]
   (when-not (parent-is-page? node)
   (when-not (parent-is-page? node)
     (let [parent-node (tree/-get-parent node)]
     (let [parent-node (tree/-get-parent node)]
+      (save-current-block!)
       (outliner-tx/transact!
       (outliner-tx/transact!
        {:outliner-op :move-blocks
        {:outliner-op :move-blocks
         :real-outliner-op :indent-outdent}
         :real-outliner-op :indent-outdent}
-       (save-current-block!)
        (outliner-core/move-blocks! [(:data node)] (:data parent-node) true)))))
        (outliner-core/move-blocks! [(:data node)] (:data parent-node) true)))))
 
 
 (defn- last-top-level-child?
 (defn- last-top-level-child?
@@ -2666,6 +2666,7 @@
 
 
 (defn indent-outdent
 (defn indent-outdent
   [indent?]
   [indent?]
+  (save-current-block!)
   (state/set-editor-op! :indent-outdent)
   (state/set-editor-op! :indent-outdent)
   (let [pos (some-> (state/get-input) cursor/pos)
   (let [pos (some-> (state/get-input) cursor/pos)
         {:keys [block]} (get-state)]
         {:keys [block]} (get-state)]
@@ -2674,8 +2675,7 @@
       (outliner-tx/transact!
       (outliner-tx/transact!
        {:outliner-op :move-blocks
        {:outliner-op :move-blocks
         :real-outliner-op :indent-outdent}
         :real-outliner-op :indent-outdent}
-       (save-current-block!)
-       (outliner-core/indent-outdent-blocks! [block] indent?)))
+        (outliner-core/indent-outdent-blocks! [block] indent?)))
     (state/set-editor-op! :nil)))
     (state/set-editor-op! :nil)))
 
 
 (defn keydown-tab-handler
 (defn keydown-tab-handler

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

@@ -99,4 +99,4 @@
         (for [command commands]
         (for [command commands]
           command)]
           command)]
        [:div.toolbar-hide-keyboard
        [:div.toolbar-hide-keyboard
-        (command #(state/clear-edit!) "keyboard-show")]])))
+        (command #(state/clear-edit!) {:icon "keyboard-show"})]])))

+ 34 - 34
static/yarn.lock

@@ -392,41 +392,41 @@
   resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
   resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
   integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
   integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
 
 
-"@logseq/[email protected].59":
-  version "0.0.59"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-arm64/-/rsapi-darwin-arm64-0.0.59.tgz#3b478c1e045246a536446b39ee0df6943403ec8f"
-  integrity sha512-mi7Z8UVocVGayCB2kKUgq6MGRNI7BX9EZeTnf7JWRLdfVZe4Rf3FDe1Kr/zlY5lO27KYsPzqLC/Pw6IkQtZsvQ==
-
-"@logseq/[email protected].59":
-  version "0.0.59"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-x64/-/rsapi-darwin-x64-0.0.59.tgz#7a3d746d4807523dfe0197658d1f1266c66534f3"
-  integrity sha512-hDf5QUa+vQRHJ7p0OBAREWYOwHepUpDUEIbyXhSzTb7g5vsr5yBEOygnRt1Jt6a1DfadMPDdrl925AaUrkZAjA==
-
-"@logseq/[email protected].59":
-  version "0.0.59"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-arm64-gnu/-/rsapi-linux-arm64-gnu-0.0.59.tgz#58e83687912deae39e6e15e57093e558d80cf7ea"
-  integrity sha512-3kqeSsIjPgd+O/DvhsawJIXdIa4aPVxNtmQ/YJeyXV7Alx5jPY1kPaxKsZUl6h3qr8Zrr5/wTtg0pUS33BwHPg==
-
-"@logseq/[email protected].59":
-  version "0.0.59"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-x64-gnu/-/rsapi-linux-x64-gnu-0.0.59.tgz#5dd228df20befbd642044d99e0a41df86d9cdda5"
-  integrity sha512-iBTxAlQNKX4g4AMJa2l4tOlActXchIFf0tFrNkSWKmyW1mi2AyQ78eObl90F9H1OAHbziOhOs+zzu8nZvJBIJQ==
-
-"@logseq/[email protected].59":
-  version "0.0.59"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi-win32-x64-msvc/-/rsapi-win32-x64-msvc-0.0.59.tgz#3a44b310ad8fa725cd2d1cb6056dc5d66fa644b2"
-  integrity sha512-tupB5/uxcChl6PZO1Wb1g9w8MpiMArM9wu4d2b0KGTccOExKrMwZzKcusFfgWsCqwiIqF2ozBPVd8JKMnAd+yw==
-
-"@logseq/[email protected].59":
-  version "0.0.59"
-  resolved "https://registry.yarnpkg.com/@logseq/rsapi/-/rsapi-0.0.59.tgz#94b359237632279e2ccaf58fbbd563b0718307dc"
-  integrity sha512-m3Y4/k2VmyuLLrNo1EuSBOiNASXrZHtC8bsN2a/AyHFeFuCDThqiTNJ0g5VqvqeaQBBZBaIUawg3OKsmjkRHhQ==
+"@logseq/[email protected].60":
+  version "0.0.60"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-arm64/-/rsapi-darwin-arm64-0.0.60.tgz#5edd887b38dd4d26cae51d397ff0c6f3d96bec43"
+  integrity sha512-Bv0ck+pjHb0z6OaGbuIl4RNbKF1KRF281zDdpiVisdSByVQ6sCQ55lemvgDFgwlZWp3Bp6vyMTrfjlzeuP86ZQ==
+
+"@logseq/[email protected].60":
+  version "0.0.60"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-x64/-/rsapi-darwin-x64-0.0.60.tgz#3c099b77f6e4fa5578a61de83e9907bfaf3ac3fa"
+  integrity sha512-iasBB89fB1h5kWAfrV2DQcynlUMKdR85GyruaVbJYspYp0SlkB+ZiR9vh5lkJQyNkMM8Y1hvLRh2ZTMAl+acWA==
+
+"@logseq/[email protected].60":
+  version "0.0.60"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-arm64-gnu/-/rsapi-linux-arm64-gnu-0.0.60.tgz#77e6ef67e87c975ca6a639da3a0b47a69afad8e7"
+  integrity sha512-op47HnJZUKYvrHsMFnlzkTd5uMeYCGkQXF1bYvYYgQrgREJyU2CzJHKKDoFZth13ahF8rjAccHeXhqg3TGccSg==
+
+"@logseq/[email protected].60":
+  version "0.0.60"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-x64-gnu/-/rsapi-linux-x64-gnu-0.0.60.tgz#fd96e37e902d9b4b031c603ec4fe1d06d9b2e594"
+  integrity sha512-LeM/PrGdVH3ix43erCVkKM0N5saXhJG7yxNl000/4bNAUkqdGOQ2Cnhy/TyekgZtMqblKjDl/1tJWboLA5jjLQ==
+
+"@logseq/[email protected].60":
+  version "0.0.60"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi-win32-x64-msvc/-/rsapi-win32-x64-msvc-0.0.60.tgz#ed2d072df731c01681c4a24caf5a26baa5ff37a9"
+  integrity sha512-22/RRF/VUAb5flW2DLkG0RUMj+LujghSP9pMgv2zkyap104HG1+Wy8xO4j1DkqtpZnwVd2MCohVuHeimHn8IMA==
+
+"@logseq/[email protected].60":
+  version "0.0.60"
+  resolved "https://registry.yarnpkg.com/@logseq/rsapi/-/rsapi-0.0.60.tgz#45763b9988e558c0e9513826cf55069ea0a413c1"
+  integrity sha512-fn2tdNyx8XCvh100YG3yD5yBI+kjv0Hz9WeFKFMHb/8JujwS/MnZdM/IKDbw+JtDp/46TfXPXttLm6FQBa7O2w==
   optionalDependencies:
   optionalDependencies:
-    "@logseq/rsapi-darwin-arm64" "0.0.59"
-    "@logseq/rsapi-darwin-x64" "0.0.59"
-    "@logseq/rsapi-linux-arm64-gnu" "0.0.59"
-    "@logseq/rsapi-linux-x64-gnu" "0.0.59"
-    "@logseq/rsapi-win32-x64-msvc" "0.0.59"
+    "@logseq/rsapi-darwin-arm64" "0.0.60"
+    "@logseq/rsapi-darwin-x64" "0.0.60"
+    "@logseq/rsapi-linux-arm64-gnu" "0.0.60"
+    "@logseq/rsapi-linux-x64-gnu" "0.0.60"
+    "@logseq/rsapi-win32-x64-msvc" "0.0.60"
 
 
 "@malept/cross-spawn-promise@^1.0.0", "@malept/cross-spawn-promise@^1.1.0":
 "@malept/cross-spawn-promise@^1.0.0", "@malept/cross-spawn-promise@^1.1.0":
   version "1.1.1"
   version "1.1.1"

+ 4 - 4
yarn.lock

@@ -487,10 +487,10 @@
     "@jridgewell/resolve-uri" "^3.0.3"
     "@jridgewell/resolve-uri" "^3.0.3"
     "@jridgewell/sourcemap-codec" "^1.4.10"
     "@jridgewell/sourcemap-codec" "^1.4.10"
 
 
-"@logseq/[email protected]7":
-  version "0.0.17"
-  resolved "https://registry.yarnpkg.com/@logseq/capacitor-file-sync/-/capacitor-file-sync-0.0.17.tgz#4bb9000c64aee8cc07d79069f5e3cbc0908b2613"
-  integrity sha512-B+VHtmH9tGNXiGcHDKNMY2Ype/YHPg+V+HaGYXqEEtzSVtw2QOe/RLkOZG+wKFhokSk3hNQyVd1/WdMGhdHS/Q==
+"@logseq/[email protected]8":
+  version "0.0.18"
+  resolved "https://registry.yarnpkg.com/@logseq/capacitor-file-sync/-/capacitor-file-sync-0.0.18.tgz#9e6c1386483fb693ce5fdd5b5a3fbb8627de40fc"
+  integrity sha512-tRcwc9OBh4oayhbMGj9iL+86jsUAT+Y76mLqsdYGsbKhck4Hv+YV3dZ0M9GUEFf18xE1pj6H7sB+qYGMd23X6w==
 
 
 "@logseq/[email protected]":
 "@logseq/[email protected]":
   version "1.3.1-1"
   version "1.3.1-1"