Skip to content

Remove compact workspace row tap gestures - #6124

Merged
azooz2003-bit merged 1 commit into
mainfrom
task-remove-workspace-row-tap-gesture
Jun 14, 2026
Merged

azooz2003-bit merged 1 commit into
mainfrom
task-remove-workspace-row-tap-gesture

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jun 14, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Remove redundant simultaneousGesture(TapGesture()) from compact workspace rows and group headers.
  • Let NavigationStack(path:) drive compact navigation and sync selectedWorkspaceID from the parent path observer.

Testing

  • ./scripts/reload-cloud.sh --tag ntap (cloud unavailable, local tagged macOS build succeeded)
  • ios/scripts/reload.sh --tag ntap (iOS Simulator build/install succeeded on iPhone 17)
  • swift test --package-path Packages/CmuxMobileShellUI (blocked before compile: missing local GhosttyKit.xcframework artifact in fresh worktree)

Notes

  • No user-facing strings changed; localization audit found no new UI text.

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Removed redundant tap gestures from compact workspace rows and group headers so NavigationLink fully controls navigation. This stops duplicate taps and keeps compact selection in sync with the parent navigation path.

  • Bug Fixes
    • Removed .simultaneousGesture(TapGesture()) from compact rows and headers to avoid duplicate selection.
    • Let NavigationStack(path:) updates drive compact selection; update selectedWorkspaceID from compactNavigationPath.
    • Clear pendingCompactCreateNavigationWorkspaceIDs on any compact path update to avoid stale navigation state.

Written for commit 09cefcb. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved workspace navigation behavior for “push” interactions so tapping a workspace header/row consistently selects the correct destination.
    • Fixed stale navigation state by clearing a pending “created workspace” selection intent when the compact navigation destination changes, preventing incorrect subsequent workspace selections.

@vercel

vercel Bot commented Jun 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 14, 2026 5:29pm
cmux-staging Building Building Preview, Comment Jun 14, 2026 5:29pm

@coderabbitai

coderabbitai Bot commented Jun 14, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Three small navigation fixes in CmuxMobileShellUI: redundant simultaneousGesture calls that manually invoked selectWorkspace on .push-style NavigationLink rows are removed from WorkspaceNavigationRow and WorkspaceGroupHeaderRow, and WorkspaceShellView now clears pendingCompactCreateNavigationWorkspaceIDs whenever compactNavigationPath changes.

Changes

Push Navigation Gesture Cleanup and Stale-State Fix

Layer / File(s) Summary
Remove redundant selectWorkspace gestures from .push rows
Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceNavigationRow.swift, Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceGroupHeaderRow.swift
For navigationStyle == .push, the simultaneousGesture that manually called selectWorkspace(workspace.id) / selectWorkspace(group.anchorWorkspaceID) is deleted from both rows; NavigationLink handles navigation directly. The .sidebar path retains its explicit Button-based selectWorkspace call.
Clear pending compact navigation intent on path change
Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift
WorkspaceShellView sets pendingCompactCreateNavigationWorkspaceIDs = nil inside the compactNavigationPath change handler, preventing a stale pending navigation intent from surviving into later path updates.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~5 minutes

Possibly related PRs

  • manaflow-ai/cmux#6064: Directly modifies WorkspaceNavigationRow's .push mode tap/selection wiring, removing or altering the tap gesture that calls selectWorkspace(workspace.id).

Poem

🐇 Hop, hop — the gestures are gone,
No double-tap calling at dawn.
The NavigationLink leads the way,
Pending intents swept away,
Clean paths for every new day! ✨


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Cmux Algorithmic Complexity ❌ Error Line 124 in WorkspaceShellView.swift violates algorithmic complexity rules: compactNavigationPath.removeAll { !workspaceIDs.contains($0) } performs O(m*n) nested scan on scalable collections in hot... Convert workspaceIDs from Array to Set: let workspaceIDSet = Set(workspaceIDs); compactNavigationPath.removeAll { !workspaceIDSet.contains($0) }
✅ Passed checks (20 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Remove compact workspace row tap gestures' accurately summarizes the main change—eliminating redundant simultaneous tap gestures from compact navigation rows.
Description check ✅ Passed The description includes a clear summary of changes and testing performed, but lacks a demo video (required by template) and a completed checklist (some items unchecked or not explicitly confirmed).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed All changes are in SwiftUI View structs (intentionally MainActor), with no implicit MainActor value models, Sendable violations, or background context store access without explicit boundaries.
Cmux Swift Blocking Runtime ✅ Passed PR removes redundant gesture handlers and enhances state syncing using deterministic SwiftUI onChange modifiers. No blocking primitives (semaphores, Task.sleep, DispatchQueue, locks, polling) intro...
Cmux Expensive Synchronous Load ✅ Passed No expensive synchronous loaders (RestorableAgentSessionIndex.load, sysctl, disk I/O) added to interactive paths; only lightweight UI state updates via selectWorkspace.
Cmux Cache Substitution Correctness ✅ Passed PR removes tap gesture handling from NavigationLink in transient UI navigation paths. No disk-persisted cache substitution occurs; compactNavigationPath is transient @State and selectedWorkspaceID...
Cmux No Hacky Sleeps ✅ Passed PR contains only Swift file changes (.swift); review rules explicitly exclude Swift timing primitives. No sleep, timer, delay, or polling patterns detected in any modified files.
Cmux Swift Concurrency ✅ Passed PR removes UI gesture handling and uses NavigationStack instead; does not introduce legacy async patterns. Pre-existing Task closures in WorkspaceShellView are SwiftUI UI-framework callbacks, an al...
Cmux Swift @Concurrent ✅ Passed No @concurrent annotation violations found. Changes are primarily navigation UI refactoring. The async refreshWorkspacesClosure is correctly marked @Sendable without requiring @concurrent.
Cmux Swift File And Package Boundaries ✅ Passed All three Swift files in this PR (WorkspaceGroupHeaderRow.swift 132 lines, WorkspaceNavigationRow.swift 167 lines, WorkspaceShellView.swift 280 lines) are under 400-line threshold, contain pure UI...
Cmux Swift Logging ✅ Passed No prohibited logging patterns (print, debugPrint, dump, NSLog) found in the three modified Swift files. The PR only modifies navigation logic without introducing any logging that would violate the...
Cmux User-Facing Error Privacy ✅ Passed All user-facing text in the modified files uses properly localized L10n.string() calls with generic, safe content (e.g., "Delete", "Unread", "Expand group"). No exposed vendor names, internal provi...
Cmux Full Internationalization ✅ Passed PR introduces no new user-facing text and all existing strings already use L10n.string() with matching translations in ios/cmux/Resources/Localizable.xcstrings for all supported locales.
Cmux Swiftui State Layout ✅ Passed No SwiftUI state layout violations found. Files use existing @Observable pattern via @Bindable, proper closure-based actions instead of store references in row subtrees, and no render-time state mu...
Cmux Architecture Rethink ✅ Passed PR removes redundant tap gestures and uses NavigationStack(path:) directly; adds bidirectional onChange guards preventing infinite loops, no timing delays/observers/polling/locks, clears pending st...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR modifies only SwiftUI View components for workspace navigation; no NSWindow, NSPanel, NSWindowController, SwiftUI Window, or WindowGroup code is present or added.
Cmux Source Artifacts ✅ Passed All 3 changed files are hand-written Swift source files in legitimate package source directories (Packages/CmuxMobileShellUI/Sources/). No artifact patterns (DerivedData, .swiftpm, tmp, .iter-logs,...
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch task-remove-workspace-row-tap-gesture

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.

@greptile-apps

greptile-apps Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Removes redundant .simultaneousGesture(TapGesture()) modifiers from NavigationLink views in compact-mode workspace rows and group headers, letting NavigationStack(path:) alone drive navigation. A companion change splits the onChange(of: compactNavigationPath) guard so pendingCompactCreateNavigationWorkspaceIDs is cleared on any path-with-a-last-element change, not just when the selection differs.

  • WorkspaceNavigationRow / WorkspaceGroupHeaderRow: Drop .simultaneousGesture from the .push NavigationLink; the .sidebar Button path is unchanged.
  • WorkspaceShellView: Split the combined guard let … else { return } into two guards so stale pendingCompactCreateNavigationWorkspaceIDs is always cleared when the path advances, preventing a workspace-creation auto-navigate from firing after the user has already navigated elsewhere.

Confidence Score: 5/5

Safe to merge. Removes a redundant gesture that was fighting NavigationStack's own path management, and correctly relocates the pending-create state cleanup into the path observer.

All three files make small, focused removals or guard-clause splits. The only mutation path in compact mode is now the NavigationStack path observer, which was already properly guarded against loops. No new state, no new concurrency, no user-facing strings, and the sidebar code path is untouched.

No files require special attention.

Important Files Changed

Filename Overview
Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceNavigationRow.swift Removes .simultaneousGesture(TapGesture()) from the push-mode NavigationLink; sidebar Button path is untouched. Clean, no logic changed.
Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceGroupHeaderRow.swift Same gesture removal as WorkspaceNavigationRow for the group anchor NavigationLink in push mode; sidebar Button is unchanged.
Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift Guard split in onChange(of: compactNavigationPath) ensures pendingCompactCreateNavigationWorkspaceIDs is cleared whenever the path has a non-nil last element, even if selectedWorkspaceID already matches. Bidirectional observer pattern is pre-existing and properly guarded against loops.

Sequence Diagram

sequenceDiagram
    participant User
    participant NavigationLink
    participant compactNavigationPath
    participant onChange_path as onChange(compactNavigationPath)
    participant Store as store.selectedWorkspaceID
    participant onChange_sel as onChange(selectedWorkspaceID)

    Note over User,onChange_sel: Before PR — double-update via simultaneousGesture
    User->>NavigationLink: tap
    NavigationLink->>compactNavigationPath: append workspaceID
    NavigationLink-->>Store: simultaneousGesture calls selectWorkspace()
    NavigationLink-->>compactNavigationPath: selectWorkspace() also resets compactNavigationPath

    Note over User,onChange_sel: After PR — single path via NavigationStack
    User->>NavigationLink: tap
    NavigationLink->>compactNavigationPath: append workspaceID
    compactNavigationPath->>onChange_path: fires
    onChange_path->>onChange_path: clear pendingCompactCreateNavigationWorkspaceIDs
    onChange_path->>Store: set selectedWorkspaceID (if changed)
    Store->>onChange_sel: fires
    onChange_sel->>compactNavigationPath: pathForSelectionChange (returns same path — no-op)
Loading

Reviews (1): Last reviewed commit: "Remove compact workspace row tap gesture..." | Re-trigger Greptile

@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)
Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift (1)

113-122: ⚠️ Potential issue | 🟠 Major | ⚖️ Poor tradeoff

Move pending-intent clearing before the path-empty guard to prevent stale navigation on pop-to-root.

The current order clears pendingCompactCreateNavigationWorkspaceIDs only when path.last is non-nil. When the user pops back to the root (empty path), the early return on line 115 skips the clearing on line 117, leaving the pending one-shot creation intent set.

Concrete failure mode: User taps "Create workspace," then pops back to the root before the async creation completes. The pending set remains. When creation finishes and selectedWorkspaceID changes to the new workspace, the .onChange(of: selectedWorkspaceID) observer (lines 97–106) detects a "created workspace," clears the pending set, and pushes [newWorkspaceID] onto the path — unexpectedly navigating the user away from the root they just chose.

Pop-to-root is an explicit navigation action that should clear the pending intent, just as selectWorkspace(_:) (line 183) clears it on any manual selection.

🔧 Proposed fix: clear pending intent before checking path
 .onChange(of: compactNavigationPath) { _, path in
+    pendingCompactCreateNavigationWorkspaceIDs = nil
     guard let selectedWorkspaceID = path.last else {
         return
     }
-    pendingCompactCreateNavigationWorkspaceIDs = nil
     guard store.selectedWorkspaceID != selectedWorkspaceID else {
         return
     }
     store.selectedWorkspaceID = selectedWorkspaceID
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift`
around lines 113 - 122, The pending creation intent clearing in the onChange
closure for compactNavigationPath must happen before checking if the path is
empty, not after. Move the line pendingCompactCreateNavigationWorkspaceIDs = nil
to execute before the guard let selectedWorkspaceID = path.last check, so that
pop-to-root navigation (empty path) properly clears the pending intent and
prevents stale navigation when creation completes asynchronously.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift`:
- Around line 113-122: The pending creation intent clearing in the onChange
closure for compactNavigationPath must happen before checking if the path is
empty, not after. Move the line pendingCompactCreateNavigationWorkspaceIDs = nil
to execute before the guard let selectedWorkspaceID = path.last check, so that
pop-to-root navigation (empty path) properly clears the pending intent and
prevents stale navigation when creation completes asynchronously.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 678bbb1f-befd-40b4-9f41-77028384c593

📥 Commits

Reviewing files that changed from the base of the PR and between e412177 and 09cefcb.

📒 Files selected for processing (3)
  • Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceGroupHeaderRow.swift
  • Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceNavigationRow.swift
  • Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift
💤 Files with no reviewable changes (2)
  • Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceNavigationRow.swift
  • Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceGroupHeaderRow.swift

@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@azooz2003-bit
azooz2003-bit merged commit 74b854b into main Jun 14, 2026
31 of 35 checks passed
@azooz2003-bit
azooz2003-bit deleted the task-remove-workspace-row-tap-gesture branch June 14, 2026 18:12

This branch was successfully deployed

1 active deployment
Preview – cmux — 09cefcbc Deployed Jun 14, 2026 by vercel[bot]
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.

1 participant