Skip to content

fix: middle-click forward-navigation on Windows + sd-archive unused warnings#3068

Open
alfinaloshi wants to merge 2 commits into
spacedriveapp:mainfrom
alfinaloshi:main
Open

fix: middle-click forward-navigation on Windows + sd-archive unused warnings#3068
alfinaloshi wants to merge 2 commits into
spacedriveapp:mainfrom
alfinaloshi:main

Conversation

@alfinaloshi

@alfinaloshi alfinaloshi commented Apr 23, 2026

Copy link
Copy Markdown

Summary

  • fix(interface): Middle-clicking after browser history traversal on Windows caused unintended forward-navigation. WebView2 enters autoscroll mode on mousedown button-1; navigating back leaves a stale forward-history entry that the next middle-click triggers. Fixed by blocking mousedown button-1 default globally in ShellLayoutContent. Closes Middle-click causes forward-navigation #3008

  • chore(archive): Removed 15 compiler warnings (unused_imports, unused_variables) across 7 files in the sd-archive crate.

Test plan

  • Windows: middle-click on Overview → navigate into a Location → back → middle-click again — no forward-navigation
  • cargo check -p sd-archive produces zero unused warnings

Files changed

  • packages/interface/src/ShellLayout.tsx
  • crates/archive/src/adapter/script.rs
  • crates/archive/src/db.rs
  • crates/archive/src/engine.rs
  • crates/archive/src/schema/migration.rs
  • crates/archive/src/search/router.rs
  • crates/archive/src/search/vector.rs
  • crates/archive/src/source.rs

Note

Two focused changes: (1) Fixes a Windows-specific middle-click bug in the shell layout by preventing WebView2's autoscroll mode, which was interfering with browser navigation history. (2) Cleans up 15 unused compiler warnings across the archive crate—mostly unused imports and variables in database, adapter, and search modules.

Written by Tembo for commit 7f5123c. This will update automatically on new commits.

@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9fc3180a-dd1f-4ed9-8790-32f057539ef1

📥 Commits

Reviewing files that changed from the base of the PR and between 7f5123c and 50ea0b7.

📒 Files selected for processing (8)
  • crates/archive/src/adapter/script.rs
  • crates/archive/src/db.rs
  • crates/archive/src/engine.rs
  • crates/archive/src/schema/migration.rs
  • crates/archive/src/search/router.rs
  • crates/archive/src/search/vector.rs
  • crates/archive/src/source.rs
  • packages/interface/src/ShellLayout.tsx
💤 Files with no reviewable changes (1)
  • crates/archive/src/search/vector.rs
✅ Files skipped from review due to trivial changes (4)
  • crates/archive/src/schema/migration.rs
  • crates/archive/src/source.rs
  • crates/archive/src/search/router.rs
  • crates/archive/src/engine.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/interface/src/ShellLayout.tsx
  • crates/archive/src/adapter/script.rs
  • crates/archive/src/db.rs

Walkthrough

Adds a background stderr reader task for the script adapter; applies several small Rust import/variable cleanups; and registers a platform-gated document mousedown handler in ShellLayout to suppress middle-click autoscroll/navigation on Tauri+Windows.

Changes

Cohort / File(s) Summary
Script adapter runtime
crates/archive/src/adapter/script.rs
Spawns a background Tokio task that continuously reads the child process stderr line-by-line and logs warnings; removes an unused Pin import.
Search / DB logic tweaks
crates/archive/src/db.rs, crates/archive/src/search/router.rs, crates/archive/src/search/vector.rs
Minor refactors: adjust temporal date-range binding patterns and parameter binding in fts_search; remove unused imports (FtsHit, EMBEDDING_DIM). No behavior changes.
Engine & migration import cleanup
crates/archive/src/engine.rs, crates/archive/src/schema/migration.rs
Trim unused imports from top-level module lists; no runtime or API changes.
Source handling cleanup
crates/archive/src/source.rs
Import narrowed to PathBuf; MigrationAction::AddTable match no longer binds unused name.
Middle-click navigation fix (UI)
packages/interface/src/ShellLayout.tsx
Adds an effect that, when on Tauri + Windows, registers a document mousedown listener to prevent default handling of middle-click (button === 1) and cleans up on change/unmount.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nibble bugs and tidy imports neat,
A background watcher keeps stderr in seat.
On Windows Tauri I halt the middle-click spree,
No forward jumps now — peace for you and me.
Hop, hop, the repo hums in gentle harmony.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the two main changes: fixing middle-click forward-navigation on Windows and removing unused warnings in sd-archive.
Description check ✅ Passed The description comprehensively covers both changes with clear explanations, test plans, and file listings, though the issue closure reference is embedded in the summary text rather than in the standard 'Closes #' format.
Linked Issues check ✅ Passed The PR successfully addresses the linked issue #3008 by implementing the mousedown button-1 suppression in ShellLayoutContent to prevent WebView2 autoscroll from triggering forward-navigation.
Out of Scope Changes check ✅ Passed All changes are within scope: the interface fix directly addresses the Windows middle-click bug, and the archive changes are cleanup of unused imports/variables as stated in objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

return null;
}, [params.locationId, locationsQuery.data, currentPath]);

useEffect(() => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a global document handler; it will also affect the web build (and non-Windows desktop) by disabling middle-click default behavior everywhere. Might be worth gating to Tauri+Windows only.

Suggested change
useEffect(() => {
useEffect(() => {
if (platform.platform !== 'tauri' || !navigator.userAgent.includes('Windows')) return;
// Prevent WebView2 (Windows) from entering autoscroll mode on middle-click,
// which causes forward-navigation after browser history traversal (#3008).
const preventMiddleClickScroll = (e: MouseEvent) => {
if (e.button === 1) e.preventDefault();
};
document.addEventListener('mousedown', preventMiddleClickScroll, { passive: false });
return () => document.removeEventListener('mousedown', preventMiddleClickScroll);
}, [platform.platform]);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made suggested changes and updated

Comment thread crates/archive/src/db.rs

if let Some(ref temp) = temporal {
if let Some(date_field) = &self.schema.search.date_field {
if self.schema.search.date_field.is_some() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, but is_some() + unwrap() here is a bit brittle/less idiomatic; if let keeps it simple and avoids accidental unwraps if this block ever gets edited.

Suggested change
if self.schema.search.date_field.is_some() {
if let Some(ref temp) = temporal {
if self.schema.search.date_field.is_some() {
if let Some(after) = temp.date_after {
q = q.bind(after);
}
if let Some(before) = temp.date_before {
q = q.bind(before);
}
}
}

Comment thread crates/archive/src/adapter/script.rs Outdated
.take()
.ok_or_else(|| Error::AdapterSync("failed to open stdout".into()))?;
let stderr = child
let _stderr = child

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if you don't need stderr for parsing, dropping it without draining can deadlock the child if it writes enough to fill the pipe buffer. Logging/draining it in the background avoids that and makes adapter failures easier to diagnose.

Suggested change
let _stderr = child
let stderr = child
.stderr
.take()
.ok_or_else(|| Error::AdapterSync("failed to open stderr".into()))?;
// Best-effort: drain stderr so the child can't block on a full pipe.
tokio::spawn(async move {
let mut err_reader = BufReader::new(stderr).lines();
while let Ok(Some(line)) = err_reader.next_line().await {
tracing::warn!(line = %line, "adapter stderr");
}
});

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/archive/src/adapter/script.rs (1)

467-483: ⚠️ Potential issue | 🟠 Major

Use tokio::process::Command for async subprocess management or explicitly discard stderr to avoid deadlock.

This code uses std::process::Command in an async context and pipes stderr without consuming it. The piped stderr handle is taken but dropped immediately (renamed to _stderr to suppress the warning). If the adapter writes to stderr and fills the pipe buffer, the child process will block—while the parent is blocked reading stdout—causing a deadlock.

Either:

  1. Switch to tokio::process::Command (preferred for async code per guidelines), or
  2. Explicitly discard stderr with Stdio::null() if stderr is not needed, or
  3. Spawn a background task to drain stderr continuously.

The _stderr rename only hides the compiler warning without fixing the underlying reliability issue.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/archive/src/adapter/script.rs` around lines 467 - 483, The current
spawn block in script.rs creates a std::process::Command child, pipes stderr and
then immediately drops it (see child, stdin, stdout, _stderr and the
Error::AdapterSync errors), which can deadlock in async contexts; fix by using
tokio::process::Command for async subprocess management (replace
std::process::Command usage with tokio::process::Command and await/handle the
child via tokio APIs) or, if stderr is not needed, set .stderr(Stdio::null())
when building the command, or alternatively keep stderr piped but immediately
detach a tokio task to continuously drain the child's stderr stream (spawn a
background tokio::task::spawn that reads from the stderr handle) and only then
take stdin/stdout as done now to avoid blocking; ensure Error::AdapterSync
messages remain for failure cases.
🧹 Nitpick comments (2)
crates/archive/src/db.rs (2)

589-597: LGTM! Clearer without unused variable.

The change from if let Some(date_field) to is_some() is appropriate since the date_field variable isn't used in this block.

Minor note: Lines 590-595 use the is_some() followed by unwrap() pattern. While this works, it could be slightly safer to use if let Some(value) = temp.date_after to avoid the unwrap, but this pre-existed in the codebase and isn't introduced by this PR.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/archive/src/db.rs` around lines 589 - 597, The current block checks
self.schema.search.date_field.is_some() and then uses is_some() + unwrap() on
temp.date_after/temp.date_before before calling q = q.bind(...); replace those
is_some() + unwrap() pairs with idiomatic if let Some(value) = temp.date_after
and if let Some(value) = temp.date_before so you bind value directly (calling
q.bind(value)) and avoid unwrap; keep the outer check for
self.schema.search.date_field as-is and preserve the q = q.bind(...) calls and
variable names.

575-580: Consider using is_some() for consistency.

The pattern if let Some(_after) is valid but slightly unusual when the value isn't used—you're destructuring just to check existence. For consistency with the binding block below (line 589) and to make the intent clearer, consider using temp.date_after.is_some():

♻️ Optional refactor for consistency
 		if let Some(ref temp) = temporal {
 			if let Some(date_field) = &self.schema.search.date_field {
-				if let Some(_after) = temp.date_after {
+				if temp.date_after.is_some() {
 					sql.push_str(&format!(" AND t.\"{}\" >= ?", date_field));
 				}
-				if let Some(_before) = temp.date_before {
+				if temp.date_before.is_some() {
 					sql.push_str(&format!(" AND t.\"{}\" <= ?", date_field));
 				}
 			}
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/archive/src/db.rs` around lines 575 - 580, The code uses `if let
Some(_after) = temp.date_after` and `if let Some(_before) = temp.date_before`
solely to check existence; change these to `if temp.date_after.is_some()` and
`if temp.date_before.is_some()` to match the binding style used later and make
intent clearer; keep the same `sql.push_str(&format!(...))` calls and ensure no
other behavior changes in the block that constructs the SQL condition strings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@crates/archive/src/adapter/script.rs`:
- Around line 467-483: The current spawn block in script.rs creates a
std::process::Command child, pipes stderr and then immediately drops it (see
child, stdin, stdout, _stderr and the Error::AdapterSync errors), which can
deadlock in async contexts; fix by using tokio::process::Command for async
subprocess management (replace std::process::Command usage with
tokio::process::Command and await/handle the child via tokio APIs) or, if stderr
is not needed, set .stderr(Stdio::null()) when building the command, or
alternatively keep stderr piped but immediately detach a tokio task to
continuously drain the child's stderr stream (spawn a background
tokio::task::spawn that reads from the stderr handle) and only then take
stdin/stdout as done now to avoid blocking; ensure Error::AdapterSync messages
remain for failure cases.

---

Nitpick comments:
In `@crates/archive/src/db.rs`:
- Around line 589-597: The current block checks
self.schema.search.date_field.is_some() and then uses is_some() + unwrap() on
temp.date_after/temp.date_before before calling q = q.bind(...); replace those
is_some() + unwrap() pairs with idiomatic if let Some(value) = temp.date_after
and if let Some(value) = temp.date_before so you bind value directly (calling
q.bind(value)) and avoid unwrap; keep the outer check for
self.schema.search.date_field as-is and preserve the q = q.bind(...) calls and
variable names.
- Around line 575-580: The code uses `if let Some(_after) = temp.date_after` and
`if let Some(_before) = temp.date_before` solely to check existence; change
these to `if temp.date_after.is_some()` and `if temp.date_before.is_some()` to
match the binding style used later and make intent clearer; keep the same
`sql.push_str(&format!(...))` calls and ensure no other behavior changes in the
block that constructs the SQL condition strings.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0b2287d8-03bd-4aa7-8be3-298d5841f0b4

📥 Commits

Reviewing files that changed from the base of the PR and between 60369e9 and 7f5123c.

📒 Files selected for processing (8)
  • crates/archive/src/adapter/script.rs
  • crates/archive/src/db.rs
  • crates/archive/src/engine.rs
  • crates/archive/src/schema/migration.rs
  • crates/archive/src/search/router.rs
  • crates/archive/src/search/vector.rs
  • crates/archive/src/source.rs
  • packages/interface/src/ShellLayout.tsx
💤 Files with no reviewable changes (1)
  • crates/archive/src/search/vector.rs

…pacedriveapp#3008)

WebView2 enters autoscroll mode on middle-mousedown. After navigating
forward then back, a second middle-click exits scroll mode via the
browser forward-navigation gesture instead, causing unintended routing.

Gate to Tauri+Windows only. Prevent default on button-1 mousedown with
{passive: false} — disables WebView2 autoscroll mode, which is not
useful in a file manager.

Fixes spacedriveapp#3008
…nings

Cleans up 15 compiler warnings in sd-archive:

Unused imports removed:
- std::pin::Pin (script.rs)
- RelationsDef (db.rs)
- ConfigField, AdapterUpdateResult (engine.rs — used via full path)
- HashMap, Error, Result, FieldType, ModelDef (migration.rs)
- FtsHit (search/router.rs)
- EMBEDDING_DIM (search/vector.rs)
- Path (source.rs — only PathBuf used)

Unused variables silenced:
- _stderr in script.rs (stderr handle intentionally discarded)
- _after/_before in db.rs (presence checked via is_some later)
- date_field binding replaced with .is_some() check in db.rs
- name: _ in source.rs AddTable match arm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Middle-click causes forward-navigation

1 participant