Skip to content

Use native workspace-only bottom search on iOS - #8645

Merged
azooz2003-bit merged 55 commits into
mainfrom
task-ios-workspace-bottom-search
Jul 26, 2026
Merged

azooz2003-bit merged 55 commits into
mainfrom
task-ios-workspace-bottom-search

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jul 22, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • use the native iOS 26 search-role tab so search and the primary tab capsule share system-controlled height and alignment
  • scope searchable content to the workspace list, hide search on Notifications and pushed workspace details, and retain native tab transitions
  • preserve the workspace query across search collapse and list refresh
  • retain the navigation-bar search drawer on older iOS versions

Verification

  • testWorkspaceSearchIsMinimizedAndPreservesQueryAcrossRefresh
  • testWorkspaceSearchOnlyAppearsOnWorkspaceRoot
  • isolated iPhone 17 simulator on iOS 26.5 (cmux-wsrch-topsearch-20260722103653)
  • macOS and iOS tagged builds at 2c2287b

Summary by CodeRabbit

  • New Features

    • Added workspace and notification search, with live filtering and query persistence across refreshes and navigation.
    • Added a dedicated Search tab on iOS 26+ (scoped between workspaces and notifications).
    • Added an explicit empty state when notification search has no matching results, including new search placeholder/empty-state translations (English and Japanese).
  • Bug Fixes

    • Improved workspace search refresh/minimized search behavior and stability across primary roots.
    • Updated task composer and detail-screen chrome behavior on iOS 26+.
  • Tests

    • Expanded UI test coverage for workspace search, notification search filtering, focus behavior, refresh persistence, and empty-state handling.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Workspace and notification search state is shared through iOS shells and tab scaffolds. iOS 26 adds a dedicated search tab, notification feeds filter searchable content with localized empty states, previews and navigation are updated, and regression tests cover persistence and filtering.

Changes

Workspace and notification search experience

Layer / File(s) Summary
Bound search host and primary tab search
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListSearchHost.swift, Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobilePrimaryTabScaffold.swift
Workspace search is externally bound, with platform-specific presentation and an iOS 26 search tab that routes search to workspaces or notifications.
Notification filtering and empty states
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/NotificationFeed*.swift
Notification search text reaches the projection, filters notification content, composes with unread filtering, and renders localized no-results state.
Shell, preview, and navigation wiring
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift, Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListLayoutPreviewView.swift, Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/NotificationFeedPreviewView.swift, ios/cmux/Resources/Localizable.xcstrings
Shell and preview state is bound into search hosts and scaffolds; task-composer, toolbar, route navigation, and search localization are updated.
Projection and iOS UI validation
Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/NotificationFeedProjectionTests.swift, ios/cmuxUITests/cmuxUITests.swift
Tests cover asynchronous notification filtering, workspace search persistence across refresh and roots, notification filtering, and keyboard handling.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant WorkspaceShellView
  participant MobilePrimaryTabScaffold
  participant NotificationFeedView
  participant NotificationFeedProjection
  User->>WorkspaceShellView: Open primary tabs
  WorkspaceShellView->>MobilePrimaryTabScaffold: Bind workspace and notification search text
  User->>MobilePrimaryTabScaffold: Select Search tab
  MobilePrimaryTabScaffold->>NotificationFeedView: Apply notification searchable query
  NotificationFeedView->>NotificationFeedProjection: Update searchText
  NotificationFeedProjection->>NotificationFeedView: Return filtered notification sections
Loading

Important

Pre-merge checks failed

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

❌ Failed checks (3 errors, 1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error The diff adds production debounce in NotificationFeedProjection via ContinuousClock().sleep and a detached rebuild task; the prior code rebuilt synchronously. Remove the sleep-based debounce or move scheduling to an actor/explicit signal; keep any waits limited to test scaffolding.
Cmux Algorithmic Complexity ❌ Error Search state moved to WorkspaceShellView, so each keystroke recomputes a shell-wide projection that scans workspaces/notifications/devices; no cache or bound exists. Keep search state below the shell or memoize workspaceShellRenderPresentation/toolbar snapshots off store changes so typing doesn’t rescan all workspaces and notifications.
Cmux No Test Or Debug Seam In Production Source ❌ Error NotificationFeedProjection.swift added test-only waitForPendingRebuild() in Sources, and only tests call it, so a seam landed in production code. Move the wait helper into the test target (or widen needed state to internal and use @testable import), removing the production-source hook per PR #6452.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Cmux Swiftpm Lockfiles ❓ Inconclusive pending investigation need to inspect changed files and swiftpm-package-resolved rules against the PR diff
✅ Passed checks (20 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main change: native iOS search behavior scoped to the workspace tab.
Description check ✅ Passed The summary and verification are specific, but the template's demo video, review trigger, and checklist sections are missing.
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 Changes stay on SwiftUI/MainActor paths; detached feed rebuild uses Sendable snapshots and store calls hop through @MainActor methods, so no new isolation regression.
Cmux Browser Automation Off-Main ✅ Passed Diff only changes notification-feed search/status/tests; no browser.* commands, socketWorkerMethods, or mainActor routing appear in the changed files.
Cmux Expensive Synchronous Load ✅ Passed No new synchronous agent-history/session/JSON load was added; the PR only wires search state and keeps projection rebuilding on Task.detached/background work.
Cmux Cache Substitution Correctness ✅ Passed Transient UI-only cache: NotificationFeedProjection falls back to sourceItems on cold cache and guards writes with sourceRevision/rebuildRevision, so no stale persistence path.
Cmux No Hacky Sleeps ✅ Passed PR touches only Swift files; the only wait is a Swift ContinuousClock.sleep debounce, which is out of scope for this non-Swift no-hacky-sleeps check.
Cmux Swift Concurrency ✅ Passed No new DispatchQueue/Combine/completion-handler patterns; async work is SwiftUI-bound or a stored, cancellable rebuild Task, not unmanaged fire-and-forget.
Cmux Swift @Concurrent ✅ Passed New async work is either @MainActor/UI-bound or explicitly hops via Task.detached; no missing or invalid @concurrent was introduced.
Cmux Swift Package Boundaries ✅ Passed All production Swift changes are in Packages/iOS/CmuxMobileShellUI/Sources; the only non-package Swift file is a UITest, so no app-target boundary violation.
Cmux Swift Logging ✅ Passed The PR diff adds no print/debugPrint/dump/NSLog/Logger changes in the touched Swift files.
Cmux User-Facing Error Privacy ✅ Passed PASS: the diff only adds generic search placeholders and empty-state copy; no vendor/internal details, secrets, or recovery/error text appear in the changed user-facing strings.
Cmux Full Internationalization ✅ Passed New production-facing text is localized via L10n/String(localized:), all 60 referenced keys exist with en/ja translations, and remaining literals are DEBUG-only previews.
Cmux Swiftui State Layout ✅ Passed Diff uses @Observable, not ObservableObject/@published, and no GeometryReader, lazy-row store refs, or render-time state writes were introduced.
Cmux Architecture Rethink ✅ Passed Search state has clear owners/bindings and the iOS 26 tab/search bridge is explicit; no new symptom-patch timing or split ownership is introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS: The diff only touches SwiftUI views/previews/tabs/search; no NSWindow/NSPanel/NSWindowController/Window/WindowGroup or cmux.* window-registration changes were introduced.
Cmux Source Artifacts ✅ Passed All changed paths are source/test files; no logs, screenshots, build output, caches, DerivedData, or scratch dirs appear in the diff.
Cmux No Ambient Global State ✅ Passed No new file-scope mutable state or singletons; the PR moves search state into owning views/projections via bindings and instance properties.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch task-ios-workspace-bottom-search

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.

@greptile-apps

greptile-apps Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds native workspace-only search on iOS 26 and expands the mobile notification feed. The main changes are:

  • Native search-tab presentation with workspace-scoped query persistence.
  • Root-only search visibility and native task-composer placement.
  • Notification filtering, routing, empty states, and bounded feed decoding.
  • Feed aggregation, persistence recovery, localization, and UI coverage.

Confidence Score: 5/5

This looks safe to merge.

  • The updated search lifecycle preserves queries across refreshes and presentation changes.
  • Stale platform callbacks no longer end an active search.
  • Native toolbar placement removes the overlapping and duplicate composer paths.
  • No blocking issue remains in the reviewed fixes.

Important Files Changed

Filename Overview
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobilePrimarySearchCoordinator.swift Coordinates native search lifecycle, query commits, scope changes, and stale callback handling.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListSearchHost.swift Uses native iOS 26 search and bottom-toolbar placement while retaining the older navigation-bar search path.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobilePrimaryTabScaffold.swift Connects native search presentation, tab selection, destination scope, and lifecycle callbacks.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift Routes workspace search and task composition through the native iOS 26 layout.

Reviews (52): Last reviewed commit: "fix(ios): use native task composer toolb..." | Re-trigger Greptile

Comment on lines +192 to +196
.onChange(of: isVisible) { _, visible in
guard !visible else { return }
searchText = ""
isPresented = false
}

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.

P1 Hidden Control Erases Shared Query

When navigation, a tab switch, or a compact-to-split layout change hides this root-only control, this observer clears the shell-owned query. The native split search then receives an empty binding, and returning to Workspaces loses the user's filter even though only the presentation changed.

Rule Used: Flag Swift fixes that patch symptoms while leaving... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +182 to +189
.overlay(alignment: .bottomTrailing) {
if isVisible {
WorkspaceListBottomSearchControl(
searchText: $searchText,
isPresented: $isPresented,
taskComposerAction: taskComposerAction
)
.padding(.bottom, 8)

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.

P2 Overlay Can Cover Tab Controls

On the iOS 26 compact root, this modifier overlays a 52-point control only eight points above the bottom of the entire TabView, where the floating tab bar also renders. If the tab bar occupies that trailing area, the search control can overlap its buttons and intercept primary tab navigation; the placement should use the tab-bar accessory or safe-area layout supplied by the platform instead of an unrestricted overlay.

@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.

Actionable comments posted: 2

🤖 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.

Inline comments:
In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListSearchHost.swift`:
- Around line 97-107: Update the isPresented change handling in
WorkspaceListSearchHost to avoid relying on Task.yield scheduling before setting
searchIsFocused. Keep the TextField mounted while toggling its visibility, or
trigger focus from a presentation-completion signal so focus occurs reliably
after presentation.

In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift`:
- Around line 696-715: Refactor taskComposerButtonOverlay so the iOS
availability and usesCompactStack conditions produce a single boolean
determining whether the button is shown, then render one TaskComposerButton with
its existing action and padding modifiers. Preserve the current behavior: show
it when taskComposerEnabled and workspaceSearchIsPresented is false, except on
iOS 26+ when usesCompactStack is true.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 89b83adb-e8a8-4ed2-b1b4-c25163a8a44e

📥 Commits

Reviewing files that changed from the base of the PR and between 49a43bf and 012885e.

📒 Files selected for processing (6)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerButton.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListLayoutPreviewView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListSearchHost.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift
  • ios/cmux/Resources/Localizable.xcstrings
  • ios/cmuxUITests/cmuxUITests.swift

Comment on lines +97 to +107
.onChange(of: isPresented, initial: true) { _, presented in
guard presented else {
searchIsFocused = false
return
}
Task { @MainActor in
await Task.yield()
guard isPresented else { return }
searchIsFocused = true
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🌐 Web query:

Does SwiftUI FocusState require the focused view to already be mounted, or is a Task.yield after presenting it a common workaround?

💡 Result:

Yes, SwiftUI FocusState effectively requires the target view to be mounted and rendered within the view hierarchy before it can successfully accept focus [1]. When you attempt to set focus programmatically (e.g., in onAppear) before the view has fully finished its layout or navigation transition, the operation is often ignored because the view's focus node has not yet been established [1][2]. Using a delay, such as Task.yield or Task.sleep, is a widely recognized and common workaround for this behavior [3][4][5][6]. Because SwiftUI's focus system manages focus nodes during the rendering pass, waiting until the next turn of the run loop or allowing the view hierarchy to stabilize ensures that the target view is ready to become the first responder [1][4][2]. Common implementations include: 1. Using the.task modifier: This is often preferred over onAppear as it is designed for asynchronous operations [3][4]. 2. Introducing an asynchronous delay: Wrapping the focus assignment in Task { await Task.yield; focus =... } or a short Task.sleep allows the view hierarchy sufficient time to complete its setup [3][1][5][6]. While sometimes effective, relying on these delays is often necessary due to the way SwiftUI synchronizes focus state with the underlying platform's responder chain, particularly during initial view loading or navigation transitions [1][2][7].

Citations:


🏁 Script executed:

sed -n '1,180p' Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListSearchHost.swift

Repository: manaflow-ai/cmux

Length of output: 6344


🏁 Script executed:

sed -n '180,320p' Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListSearchHost.swift

Repository: manaflow-ai/cmux

Length of output: 1632


Avoid yielding before focusing the search field

Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListSearchHost.swift:97-107
TextField is only inserted when isPresented becomes true, so Task { await Task.yield(); searchIsFocused = true } still depends on scheduling to win the mount race. Keep the field mounted and toggle visibility, or drive focus from a presentation-completion signal instead.

🤖 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/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListSearchHost.swift`
around lines 97 - 107, Update the isPresented change handling in
WorkspaceListSearchHost to avoid relying on Task.yield scheduling before setting
searchIsFocused. Keep the TextField mounted while toggling its visibility, or
trigger focus from a presentation-completion signal so focus occurs reliably
after presentation.

Source: Coding guidelines

@azooz2003-bit azooz2003-bit changed the title Add workspace-only bottom search on iOS Use native workspace-only bottom search on iOS Jul 22, 2026

@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.

Actionable comments posted: 2

🤖 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.

Inline comments:
In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListSearchHost.swift`:
- Around line 39-46: Add the three mobile localization
keys—mobile.workspaces.search.placeholder,
mobile.taskComposer.button.accessibilityLabel, and
mobile.taskComposer.button.accessibilityHint—to every supported locale in the
project’s referenced string catalog(s), preserving the existing English and
Japanese entries and providing valid localized values for all remaining locales.

In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift`:
- Around line 356-358: Consolidate the repeated task-composer presentation
closure into a single shared openTaskComposer method or computed closure in
WorkspaceShellView. Replace the taskComposerAction in stackLayout and both
actions in taskComposerButtonOverlay with this shared action, preserving the
existing isTaskComposerPresented = true behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 496f295d-2daf-42e9-9982-054a3de0c518

📥 Commits

Reviewing files that changed from the base of the PR and between 012885e and 8288249.

📒 Files selected for processing (5)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListLayoutPreviewView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListSearchHost.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift
  • ios/cmux/Resources/Localizable.xcstrings
  • ios/cmuxUITests/cmuxUITests.swift
💤 Files with no reviewable changes (1)
  • ios/cmux/Resources/Localizable.xcstrings

Comment on lines +39 to +46
.searchable(
text: $searchText,
prompt: L10n.string(
"mobile.workspaces.search.placeholder",
defaultValue: "Search workspaces"
)
)
.searchToolbarBehavior(.minimize)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -a Localizable.xcstrings
python3 - <<'PY'
import json
path = "ios/cmux/Resources/Localizable.xcstrings"
try:
    data = json.load(open(path))
except FileNotFoundError:
    print("xcstrings file not found at expected path")
    raise SystemExit(0)
keys = [
    "mobile.workspaces.search.placeholder",
    "mobile.taskComposer.button.accessibilityLabel",
    "mobile.taskComposer.button.accessibilityHint",
]
for k in keys:
    entry = data.get("strings", {}).get(k)
    if entry is None:
        print(f"MISSING KEY: {k}")
        continue
    locs = entry.get("localizations", {})
    print(f"{k}: locales={sorted(locs.keys())}")
PY

Repository: manaflow-ai/cmux

Length of output: 1502


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== L10n/localization code around WorkspaceListSearchHost =="
fd -a WorkspaceListSearchHost.swift . | sed 's#^\./##' | while read -r f; do
  echo "--- $f"
  wc -l "$f"
  nl -ba "$f" | sed -n '1,120p'
done

echo "== referenced xcstrings size/tops =="
wc -l ios/cmux/Resources/Localizable.xcstrings Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/Resources/Localizable.xcstrings

echo "== targeted key occurrences =="
rg -n "mobile\.workspaces\.search\.placeholder|mobile\.taskComposer\.button\.accessibility" -S .

echo "== xcstrings key entries =="
python3 - <<'PY'
import json, pathlib
for path in ["ios/cmux/Resources/Localizable.xcstrings", "Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/Resources/Localizable.xcstrings"]:
    p=pathlib.Path(path)
    print(f"--- {path}")
    if not p.exists():
        print("missing")
        continue
    data=json.loads(p.read_text())
    for k in ["mobile.workspaces.search.placeholder","mobile.taskComposer.button.accessibilityLabel","mobile.taskComposer.button.accessibilityHint"]:
        entry=data.get("strings",{}).get(k)
        if entry:
            locs=entry.get("localizations",{})
            print(k)
            for loc,(translated,unit) in locs.items():
                s=unit.get("stringUnit",{})
                print(f"  {loc}: value={s.get('value')!r}")
        else:
            print(f"MISSING {k}")
PY

Repository: manaflow-ai/cmux

Length of output: 473


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== WorkspaceListSearchHost.swift locations and key occurrences =="
fd -a WorkspaceListSearchHost.swift .

echo
for f in $(fd WorkspaceListSearchHost.swift .); do
  echo "--- $f"
  cat -n "$f" | sed -n '1,120p'
done

echo "== localized key search across all tracked Swift files =="
rg -n "mobile\.workspaces\.search\.placeholder|mobile\.taskComposer\.button\.accessibility" -S --glob '*.swift' . || true

echo "== supported locale entries in referenced xcstrings =="
python3 - <<'PY'
import json, pathlib
for path in ["ios/cmux/Resources/Localizable.xcstrings", "Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/Resources/Localizable.xcstrings"]:
    p=pathlib.Path(path)
    print(f"--- {path}")
    if not p.exists():
        print("missing")
        continue
    try:
        data=json.loads(p.read_text())
    except Exception as e:
        print(f"json error: {e}")
        continue
    metas=data.get("metalizations",{}) or data.get("manifest",{}).get("localizations",{}) or data.get("localizations",{})
    print("top meta keys:", sorted(data.keys()))
    print("localizations:", sorted(metas.keys()) if isinstance(metas, dict) else type(metas).__name__)
    for k in ["mobile.workspaces.search.placeholder","mobile.taskComposer.button.accessibilityLabel","mobile.taskComposer.button.accessibilityHint"]:
        entry=data.get("strings",{}).get(k)
        if entry:
            print(k, "localizations=", sorted(entry.get("localizations",{}).keys()))
            for loc,unit in sorted(entry.get("localizations",{}).items()):
                print(f"  {loc}:", repr(unit.get("stringUnit",{}).get("value")))
        else:
            print("MISSING", k)
PY

Repository: manaflow-ai/cmux

Length of output: 5905


Add the new mobile localization key entries to every supported locale.

L10n.string now uses these keys, but the catalog only contains en and ja entries. Extend mobile.workspaces.search.placeholder, mobile.taskComposer.button.accessibilityLabel, and mobile.taskComposer.button.accessibilityHint to all supported locales in the referenced string catalog(s) to avoid broken fallback for unsupported locales.

🤖 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/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListSearchHost.swift`
around lines 39 - 46, Add the three mobile localization
keys—mobile.workspaces.search.placeholder,
mobile.taskComposer.button.accessibilityLabel, and
mobile.taskComposer.button.accessibilityHint—to every supported locale in the
project’s referenced string catalog(s), preserving the existing English and
Japanese entries and providing valid localized values for all remaining locales.

Comment thread Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift Outdated

@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)
ios/cmuxUITests/cmuxUITests.swift (1)

5044-5047: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Replacing "Return" with "Search" in the default keyboard-dismiss fallback list risks breaking dismissal for other fields.

dismissKeyboard(in:)'s default fallback list drops "Return" in favor of "Search". This list is shared by tap(_:in:), typeText, and replaceText, which back dozens of pre-existing tests against plain single-line fields (prompts, folder search's non-add-device paths, template names, etc.) that typically show a "Return"-labeled key, not "Done"/"Search"/"Next". Narrowing the list (instead of adding "Search" alongside "Return") can silently leave the keyboard up for those fields going forward.

🐛 Proposed fix
         let fallbackLabels = preferAddDeviceAccessoryDoneButton
             ? ["Done", "Return", "Next"]
-            : ["Done", "Search", "Next"]
+            : ["Done", "Return", "Search", "Next"]
🤖 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 `@ios/cmuxUITests/cmuxUITests.swift` around lines 5044 - 5047, Update the
default fallback labels in dismissKeyboard(in:) to retain "Return" and add
"Search" alongside the existing labels, while preserving the
preferAddDeviceAccessoryDoneButton-specific behavior. Ensure shared callers such
as tap(_:in:), typeText, and replaceText continue dismissing keyboards for
fields exposing a "Return" key.
🤖 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 `@ios/cmuxUITests/cmuxUITests.swift`:
- Around line 5044-5047: Update the default fallback labels in
dismissKeyboard(in:) to retain "Return" and add "Search" alongside the existing
labels, while preserving the preferAddDeviceAccessoryDoneButton-specific
behavior. Ensure shared callers such as tap(_:in:), typeText, and replaceText
continue dismissing keyboards for fields exposing a "Return" key.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6e47c04a-a8fd-46f4-83ac-806512f108fb

📥 Commits

Reviewing files that changed from the base of the PR and between 8288249 and 2c2287b.

📒 Files selected for processing (6)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobilePrimaryTabScaffold.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/NotificationFeedPreviewView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListLayoutPreviewView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListSearchHost.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift
  • ios/cmuxUITests/cmuxUITests.swift

@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.

Actionable comments posted: 3

🤖 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.

Inline comments:
In `@ios/cmuxUITests/cmuxUITests.swift`:
- Around line 452-481: Update the search button frame snapshots in the test
around searchButton to use waitForUsableFrame instead of reading frame directly
after existence. Apply it to both the initial snapshot and the final frame
before comparing them, while preserving the existing existence and equality
assertions.
- Around line 410-418: Update the filtering assertions in
ios/cmuxUITests/cmuxUITests.swift at lines 410-418 and 540-547: before
searching, assert the relevant fixture rows are hittable; afterward, require the
expected matching row to become or remain hittable rather than relying on
waitForNotHittable. Preserve the existing workspace-tab and keyboard-dismissal
flow while using real visibility/hittability completion signals to prove
filtering.
- Around line 5194-5196: Update the fallbackLabels definition in the
dismissKeyboard flow to retain “Return” as a generic keyboard fallback while
also adding “Search” for search keyboards; do not replace or remove the existing
“Return” label.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 62e2d330-1519-494e-9bb3-c1b973c21abf

📥 Commits

Reviewing files that changed from the base of the PR and between 2c2287b and 2fa4df3.

📒 Files selected for processing (11)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobilePrimaryTabScaffold.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/NotificationFeedPreviewView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/NotificationFeedProjection.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/NotificationFeedStatusView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/NotificationFeedStoreView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/NotificationFeedView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListLayoutPreviewView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/NotificationFeedProjectionTests.swift
  • ios/cmux/Resources/Localizable.xcstrings
  • ios/cmuxUITests/cmuxUITests.swift

Comment thread ios/cmuxUITests/cmuxUITests.swift Outdated
Comment thread ios/cmuxUITests/cmuxUITests.swift Outdated
Comment thread ios/cmuxUITests/cmuxUITests.swift Outdated

@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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/NotificationFeedProjection.swift`:
- Around line 76-127: Add a brief doc comment immediately above scheduleRebuild
describing its debounce behavior, sourceRevision-keyed index caching,
cancellation, and the invariant that only a task whose captured rebuildRevision
and sourceRevision still match self may write results. Keep the implementation
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a505a220-c920-4a47-b099-e55940289033

📥 Commits

Reviewing files that changed from the base of the PR and between 2fa4df3 and 4dc5f9e.

📒 Files selected for processing (3)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/NotificationFeedProjection.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/NotificationFeedStatusView.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/NotificationFeedProjectionTests.swift

Comment on lines +251 to +255
private func beginSearchDeactivation(for scope: MobilePrimarySearchScope) {
searchPhase = .deactivating(scope)
pendingEmptyCommit = nil
syncNativeSearchText(fromCommittedQueryFor: scope)
}

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.

P1 Clear action gets reverted

When the user clears a non-empty query and then dismisses search, commitNativeSearchText leaves the clear in pendingEmptyCommit. This deactivation path deletes that pending change and copies the old committed query back into the native field. Reopening search therefore restores the query the user explicitly cleared. The lifecycle state needs to preserve queries on presentation-only dismissal without treating a user clear as presentation cleanup.

Rule Used: Flag Swift fixes that patch symptoms while leaving... (source)

@cursor

cursor Bot commented Jul 25, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Jul 25, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Jul 25, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Jul 25, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

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