Skip to content

iOS: custom sort for the All Computers workspace list - #9828

Merged
azooz2003-bit merged 11 commits into
mainfrom
feat-ios-all-computers-sort
Aug 9, 2026
Merged

azooz2003-bit merged 11 commits into
mainfrom
feat-ios-all-computers-sort

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Aug 7, 2026 •

Copy link
Copy Markdown
Collaborator

Workspaces from different computers have no deterministic cross-Mac ordering of their own (each Mac only owns its sidebar order), so this makes the aggregate order a device-local, user-controlled choice. A new Sort By section in the workspace-list filter menu (All Computers scope only, 2+ computers) offers three modes:

  • Automatic — foreground computer first, then name. The old behavior, still the default.
  • Computer Order — computers in a user-dragged priority order (new reorder sheet, auto-opens on first pick so the mode is never silently inert); each computer's workspaces keep the Mac's own sidebar order, and prioritized computers rank ahead of even the foreground Mac. Sibling builds of one Mac stay adjacent, offline computers keep their slot.
  • Recent Activity — one flat list across every computer, latest lastActivityAt first, pinned rows first, stable ties.

Mechanism: Computer Order runs inside MobileWorkspaceAggregation through the macIDsInDisplayOrder seam #9509 added, so group sections and their member rows reorder together and aggregate→Mac-local RPC translation is untouched. Recent Activity runs at the presentation layer only (MobileWorkspaceRecencyOrder), because time interleaving across Macs cannot keep one Mac's group members contiguous; it presents flat (like search/filter already do) and disables drag reorder, since a timestamp-derived order has no spatial move to send. The preference persists device-locally in MobileWorkspaceSortStore (injected UserDefaults, mirroring the group-collapse store) and never syncs to a Mac. A single-machine scope is unaffected: its order stays the Mac's own sidebar order.

Localization audit: new strings mobile.workspaces.sort(.automatic/.computerOrder/.recentActivity/.editOrder/.order.title/.order.footer) added en+ja; the sheet's Done button reuses mobile.common.done.

Tests: aggregation priority ordering (override-foreground, unknown/empty ids, sibling-build adjacency, group-follows-workspace), sort-store persistence (corrupt payload, unknown future mode preserved), recency order (pinned-first, nil-timestamp-last, stable ties) in CmuxMobileShellModelTests; scope gating, grouped-section flattening, reorder disable, and sheet ordering in CmuxMobileShellUITests.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Note

Low Risk
Presentation-layer and device-local UserDefaults preferences with broad test coverage; no Mac RPC or auth changes. Main risk is list-order edge cases (offline Macs, alias IDs, grouped vs flat modes).

Overview
Adds device-local sorting for the aggregated All Computers workspace list, with preferences stored in MobileWorkspaceSortStore and never synced to Macs.

Three modes: Last Opened (default automatic—connected Mac first, then lastSeenAt recency), Computer Order (user-ranked Macs via drag sheet; aggregation honors priority ahead of foreground), and Recent Activity (flat cross-Mac list by lastActivityAt, pinned first).

UI: The workspace filter toolbar control opens a view-options popover with illustrated sort tiles plus read-state filters; Computer Order exposes Edit Computer Order… for the reorder sheet. Sort controls appear in All Computers scope only; single-Mac views keep the Mac sidebar order. Recent Activity flattens groups and disables drag reorder.

Shell wiring: MobileShellComposite persists mode/priority, expands alias IDs for priority, and rebuilds derived workspace state when pairing or sort prefs change. Tests cover aggregation, store persistence, recency ordering, and list gating.

Reviewed by Cursor Bugbot for commit 89c0545. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Adds device‑local sorting to the All Computers workspace list with three modes: Last Opened (default), Computer Order, and Recent Activity. On iOS, a Mail‑style view‑options popover with illustrated tiles replaces the filter button; changes apply live.

  • New Features

    • View‑options popover: three illustrated sort tiles plus read‑state rows; “Edit Computer Order…” opens a drag‑to‑reorder sheet. Machine selection stays in the title picker. Shown in All Computers regardless of computer count.
    • Last Opened (formerly Automatic/Connected First): connected Mac first, then most recently used by this device (lastSeenAt); never‑opened Macs alphabetical last. UI label is “Last Opened” (raw value remains automatic).
    • Computer Order: user‑ranked Macs come first (even before foreground); sibling builds stay adjacent; paired‑but‑offline Macs keep their slot.
    • Recent Activity: flat list across all computers by lastActivityAt; pinned first; stable ties; drag‑reorder disabled. Single‑Mac scopes keep that Mac’s sidebar order.
    • Persistence and wiring: device‑local in MobileWorkspaceSortStore (UserDefaults). MobileShellComposite mirrors mode/priority and expands alias IDs. Aggregation orders via orderedMacIDs(..., computerPriority:, lastOpenedAt:); .recentActivity runs in the view via MobileWorkspaceRecencyOrder. Previews can seed mode/priority and auto‑open the popover. en/ja strings updated.
  • Bug Fixes

    • Keep “Last Opened” fresh by recomputing the derived list on pairing refresh; the order no longer goes stale after pairing updates.
    • Seed the Computer Order editor from the aggregated rows and include paired‑but‑offline Macs, so editing never drops machines.
    • Visual polish: pin the popover to regular‑weight body text, inset schematic rank badges further, and shrink the “Edit Computer Order…” row icon.

Written for commit 89c0545. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added workspace sorting options for automatic order, computer priority, and recent activity.
    • Added persistent, device-local computer ordering with drag-and-drop editing.
    • Added workspace view controls for sorting, read-state filters, and machine filters.
    • Recent activity sorting prioritizes pinned workspaces and latest activity across computers.
    • Added English and Japanese localization for sorting features.
  • Bug Fixes

    • Disabled workspace reordering when recent activity sorting is active.
    • Improved handling of duplicate, unavailable, or paired computer entries.

Workspaces from different computers have no deterministic cross-Mac order
of their own, so make the aggregate order a device-local choice with three
modes: Automatic (foreground Mac first, then name — the old behavior),
Computer Order (user drags computers into a priority order; each computer
keeps its own sidebar order), and Recent Activity (one flat list across
every computer, latest lastActivityAt first).

Computer Order runs in the aggregation (through the macIDsInDisplayOrder
seam) so group sections and workspaces reorder together. Recent Activity
runs at the presentation layer only, because time interleaving cannot keep
group members contiguous; it presents flat and disables drag reorder (a
derived order has no spatial move to send).

The preference persists in MobileWorkspaceSortStore (injected UserDefaults,
mirroring the group-collapse store) and is exposed through a Sort By picker
in the workspace list filter menu, All Computers scope only, plus a
drag-to-reorder Computer Order sheet. First-time picks of Computer Order
auto-open the editor. Strings localized en+ja.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 7, 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 sorting now supports automatic, computer-priority, and recent-activity modes. Preferences persist locally. Workspace aggregation and iOS controls apply the selected mode, including computer-order editing and recency-specific behavior.

Changes

Workspace sorting

Layer / File(s) Summary
Sorting model and persistence
Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/*, Packages/iOS/CmuxMobileShellModel/Tests/CmuxMobileShellModelTests/*
Added sorting modes, local persistence, computer-priority ordering, recent-activity ordering, and model tests.
Persisted sorting integration
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/*
Connected persisted preferences to MobileShellComposite, recomputed derived workspace state, and applied expanded computer priorities during aggregation.
iOS sorting controls and presentation
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/*, ios/cmux/Resources/Localizable.xcstrings
Added sort controls, computer-order editing, recency layout behavior, preview wiring, drag restrictions, and localized labels.
Sorting behavior validation
Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceListSortTests.swift
Added UI coverage for sorting modes, scope behavior, menu gating, reorder restrictions, persistence setup, and fixture construction.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant WorkspaceListView
  participant MobileShellComposite
  participant MobileWorkspaceSortStore
  participant MobileWorkspaceAggregation
  User->>WorkspaceListView: choose sorting mode or computer order
  WorkspaceListView->>MobileShellComposite: submit sorting change
  MobileShellComposite->>MobileWorkspaceSortStore: save preference
  MobileShellComposite->>MobileWorkspaceAggregation: recompute workspace state
  MobileWorkspaceAggregation-->>WorkspaceListView: provide ordered workspace state
Loading

Important

Pre-merge checks failed

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

❌ Failed checks (2 errors, 2 warnings)

Check name Status Explanation Resolution
Cmux Algorithmic Complexity ❌ Error MobileShellComposite+WorkspaceActions.swift:669 calls expanded.contains(alias) inside priority/alias loops, causing O(N²) rescans of stored Mac IDs during derived-state recomputation. Track emitted IDs in a Set and append only when set.insert(alias).inserted; retain the array only as the ordered output.
Cmux No Test Or Debug Seam In Production Source ❌ Error WorkspaceListView+Toolbar.swift adds a #if DEBUG CMUX_UITEST... block that auto-opens the popover for a headless harness; it is test-only behavior in production Sources. Remove the production auto-open seam and drive the UI from the test target, or isolate unavoidable screenshot/debug scaffolding in a dedicated debug file/folder; follow PR 6452.
Docstring Coverage ⚠️ Warning Docstring coverage is 5.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description gives detailed change and testing information but omits the required Demo Video, Review Trigger, and Checklist sections. Add the missing template sections, include a UI demo link or attachment, complete the checklist, and provide the review-trigger comment block.
✅ Passed checks (21 passed)
Check name Status Explanation
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 The new model helpers are pure Sendable values in Swift 6 targets without MainActor-default settings; sort persistence is accessed by the @MainActor shell, and UI callbacks stay in SwiftUI views.
Cmux Swift Blocking Runtime ✅ Passed The feature diff adds no semaphores, blocking waits, sleeps, delayed dispatch, polling, main-queue sync, timers, or manual locks; the existing preview Task.sleep is unchanged.
Cmux Browser Automation Off-Main ✅ Passed The PR changes only iOS workspace sorting and UI files; no browser socket commands, WebKit waits, worker routing, or policy files are added or modified.
Cmux Expensive Synchronous Load ✅ Passed The full PR diff adds no agent-history loader, file scan, transcript access, or contentsOf call; its only decode is the small UserDefaults sort-preference payload.
Cmux Cache Substitution Correctness ✅ Passed The diff adds a UserDefaults-backed sort preference and UI mirrors; it removes no authoritative read and adds no history, undo, or snapshot consumer that trusts a cache.
Cmux No Hacky Sleeps ✅ Passed The full PR range changes only Swift sources/tests plus Localizable.xcstrings; the rule excludes Swift and localization, and no covered non-Swift wait constructs were added.
Cmux Swift Concurrency ✅ Passed The PR adds no Dispatch, Combine, completion-handler, or fire-and-forget Task patterns; production Task and DispatchQueue counts are unchanged from origin/main.
Cmux Swift @Concurrent ✅ Passed The PR adds only synchronous sort persistence, aggregation, and SwiftUI code; no new production async functions or @concurrent annotations appear, and existing UI async work remains actor-bound.
Cmux Swift Package Boundaries ✅ Passed Production sort logic is isolated in the CmuxMobileShellModel SwiftPM target with model tests; UI is in CmuxMobileShellUI, while CmuxMobileShell changes only compose persisted state and aggregation.
Cmux Swiftpm Lockfiles ✅ Passed The full PR diff contains no Package.swift, Package.resolved, .gitignore, workflow, or Xcode project package-reference changes, so the SwiftPM lockfile policy is not triggered.
Cmux Swift Logging ✅ Passed The complete PR diff adds no print, debugPrint, dump, NSLog, stdout/file diagnostics, or Logger statements; existing unified Logger declarations and messages are unchanged.
Cmux User-Facing Error Privacy ✅ Passed The PR adds sort labels and generic ordering guidance only; no new user-facing errors, alerts, raw upstream messages, secrets, provider names, or implementation-detail diagnostics were found.
Cmux Full Internationalization ✅ Passed All new SwiftUI copy uses L10n.string with default values, and all seven changed catalog keys have translated en and ja entries in Localizable.xcstrings.
Cmux Swiftui State Layout ✅ Passed The PR adds only @State/value snapshots and closures; its new List/ForEach rows use WorkspaceFilterMachine values, with no new ObservableObject, @Published, GeometryReader, or render-time state wri...
Cmux Architecture Rethink ✅ Passed The cumulative Swift diff adds no timing, blocking, polling, lock, or observer repair; UI uses value snapshots and action closures, with the nested sheet's platform constraint documented.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR adds only SwiftUI views presented as a sheet or popover; it adds no standalone NSWindow, NSPanel, Window, WindowGroup, identifier, or close-shortcut routing.
Cmux Source Artifacts ✅ Passed The PR changes only Swift source/tests and the localization catalog; no artifact-like paths, binary additions, caches, logs, screenshots, recordings, or temp directories appear in the diff.
Cmux No Ambient Global State ✅ Passed New state is owned by injectable MobileWorkspaceSortStore (lines 11, 24-30); new behavior uses instance methods. The only new static member is the allowed defaultsKey constant, with no new globals...
Title check ✅ Passed The title clearly and concisely describes the main change: custom sorting for the iOS All Computers workspace list.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-ios-all-computers-sort

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.

@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/WorkspaceListView.swift`:
- Around line 129-130: Mark the showingComputerOrderSheet `@State` property as
private, keeping it local to the view while preserving its existing default
value and behavior.

In
`@Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceListSortTests.swift`:
- Around line 202-215: Update the shellStore helper’s UserDefaults
initialization to require the suite-specific instance instead of falling back to
UserDefaults.standard. Make suite creation failure fail the test immediately,
while preserving use of the resulting suite-scoped defaults for all repositories
and stores.
🪄 Autofix

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: 5ee3ec93-8dba-47b4-889d-d2ea81ca8eb3

📥 Commits

Reviewing files that changed from the base of the PR and between 6089fa0 and df7ee77.

📒 Files selected for processing (19)
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+WorkspaceActions.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileWorkspaceAggregation.swift
  • Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileWorkspaceRecencyOrder.swift
  • Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileWorkspaceSortMode.swift
  • Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileWorkspaceSortStore.swift
  • Packages/iOS/CmuxMobileShellModel/Tests/CmuxMobileShellModelTests/MobileWorkspaceAggregationTests.swift
  • Packages/iOS/CmuxMobileShellModel/Tests/CmuxMobileShellModelTests/MobileWorkspaceRecencyOrderTests.swift
  • Packages/iOS/CmuxMobileShellModel/Tests/CmuxMobileShellModelTests/MobileWorkspaceSortStoreTests.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceComputerOrderSheet.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListFilterControls.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListFilterMenuActions.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListLayoutPreviewView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView+DragDrop.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView+Toolbar.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceListSortTests.swift
  • ios/cmux/Resources/Localizable.xcstrings

Comment thread Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView.swift Outdated
Comment on lines +202 to +215
private func shellStore(pairedMacs: [MobilePairedMac]) async -> CMUXMobileShellStore {
let suiteName = "WorkspaceListSortTests-\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suiteName) ?? .standard
let store = MobileShellComposite(
isSignedIn: true,
connectionState: .disconnected,
pairedMacStore: WorkspaceMacSelectionPairedMacStore(pairedMacs),
clientIDRepository: MobileClientIDRepository(defaults: defaults),
identityProvider: WorkspaceMacSelectionIdentityProvider(userID: "user-1"),
teamIDProvider: { "team-a" },
pairingHintDefaults: defaults,
multiMacAggregationDefaults: defaults,
groupCollapseStore: MobileWorkspaceGroupCollapseStore(defaults: defaults),
workspaceSortStore: MobileWorkspaceSortStore(defaults: defaults)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove the UserDefaults.standard fallback.

If suite creation fails, this test uses shared persistent defaults. The test can then read or modify state from another test or the host process. Require the suite-scoped defaults and fail the test when creation fails.

Proposed fix
-        let defaults = UserDefaults(suiteName: suiteName) ?? .standard
+        let defaults = try `#require`(UserDefaults(suiteName: suiteName))
🤖 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/Tests/CmuxMobileShellUITests/WorkspaceListSortTests.swift`
around lines 202 - 215, Update the shellStore helper’s UserDefaults
initialization to require the suite-specific instance instead of falling back to
UserDefaults.standard. Make suite creation failure fail the test immediately,
while preserving use of the resulting suite-scoped defaults for all repositories
and stores.

Source: Coding guidelines

…erification

Simulator windows on another Space cannot be tap-driven without stealing
the user's display, so the fixture accepts
CMUX_UITEST_WORKSPACE_LIST_PREVIEW_SORT and ..._SORT_PRIORITY to render
each All Computers sort mode for simctl screenshot verification, matching
the existing COUNT/GROUPS seeding knobs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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

397-418: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Use the shared computer-order contract for preview workspaces.

fixtureSortedWorkspaces falls back to model.workspaces for automatic mode or an empty priority list, while MobileWorkspaceAggregation.orderedMacIDs applies automatic fallback ordering in those cases. For partial priority lists, it falls back to original row offset; production uses foreground status, display name, device ID, and instance tag. Route preview workspaces through the shared derivation, or implement the same fallback order while preserving Mac-local workspace order.

🤖 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/WorkspaceListLayoutPreviewView.swift`
around lines 397 - 418, The fixtureSortedWorkspaces implementation must match
MobileWorkspaceAggregation.orderedMacIDs for automatic and empty-priority modes
instead of returning model.workspaces directly, and for partial priority lists
must use the production fallback ordering (foreground status, display name,
device ID, then instance tag) while preserving order among workspaces on the
same Mac. Route the preview data through the shared derivation where possible;
otherwise replicate that contract in fixtureSortedWorkspaces.

Source: Coding guidelines

🤖 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/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListLayoutPreviewView.swift`:
- Around line 397-418: The fixtureSortedWorkspaces implementation must match
MobileWorkspaceAggregation.orderedMacIDs for automatic and empty-priority modes
instead of returning model.workspaces directly, and for partial priority lists
must use the production fallback ordering (foreground status, display name,
device ID, then instance tag) while preserving order among workspaces on the
same Mac. Route the preview data through the shared derivation where possible;
otherwise replicate that contract in fixtureSortedWorkspaces.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 29a3c4f8-6ab9-4db5-b0c6-46a0f7933606

📥 Commits

Reviewing files that changed from the base of the PR and between df7ee77 and fd1dc8c.

📒 Files selected for processing (1)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListLayoutPreviewView.swift

The sort section hid whenever fewer than two computers had workspace rows
on screen, so a paired-but-offline (or connection-wedged) secondary Mac
made the control undiscoverable exactly when cross-computer order matters.
Gate on distinct known computers instead: machines with visible rows plus
every paired Mac. The computer-order editor now also lists paired-but-
offline computers so they keep their slot while disconnected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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/WorkspaceListView.swift`:
- Around line 260-273: Update computerOrderSheetMachines to deduplicate the
initial filterMachines collection by physical macDeviceID before sorting or
merging paired Macs. Retain one representative ID per macDeviceID, while
preserving separate entries only when distinct build-label instances are
required, so workspaceComputerPriority receives no duplicate physical-Mac IDs.
🪄 Autofix

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: 7c31d707-bd04-4aca-a6ea-3e9a7464dea3

📥 Commits

Reviewing files that changed from the base of the PR and between fd1dc8c and 0a866ca.

📒 Files selected for processing (3)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListFilterControls.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceListSortTests.swift

azooz2003-bit and others added 2 commits August 7, 2026 20:46
The preference is worth setting before a second computer pairs, and any
count gate hides the control behind connection state (a wedged secondary
Mac already did once). All Computers scope alone decides visibility now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sort hidden inside a filter-icon menu was undiscoverable, and a text-only
'Computer Order' label communicates nothing. Replace the filter Menu with
a menu-styled popover whose top row is three drawn schematic tiles, each a
miniature of what the mode does to the list (computer sections; ranked
sections with drag grips; a flat time-stamped run), with Mail-style radio
checks. Selection re-sorts the list live behind the card. The computer-
order editor presents from the card itself, and the filter rows (read
state, machines) share it, keeping one entry point. UIMenu rows only
render text plus icon-sized images, hence a popover rather than a Menu.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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/WorkspaceListView.swift`:
- Around line 129-130: Resolve the private_swiftui_state warning for
showingViewOptionsPopover in WorkspaceListView without breaking its access from
viewOptionsButton in WorkspaceListView+Toolbar.swift: either move
viewOptionsButton into the same file and make the state private, or retain
internal access and add a targeted next-line SwiftLint suppression documenting
the cross-file usage.

In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView`+Toolbar.swift:
- Around line 28-38: The DEBUG onAppear branch checks
CMUX_UITEST_WORKSPACE_LIST_PREVIEW_VIEW_OPTIONS, but the preview fixture uses
CMUX_UITEST_WORKSPACE_LIST_PREVIEW. Update the layout-preview fixture/config
path to assign the checked variable when the popover preview is intended, or
remove the onAppear branch if it is not needed.
🪄 Autofix

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: 360c7292-6abc-4238-ac25-9446ca90ad73

📥 Commits

Reviewing files that changed from the base of the PR and between 8bc3164 and 17887c3.

📒 Files selected for processing (5)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListFilterControls.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListFilterMenuActions.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView+Toolbar.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListViewOptionsPopover.swift

Comment on lines +129 to +130
/// Presents the view-options card (sort tiles + filter rows).
@State var showingViewOptionsPopover = false

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 | 🔵 Trivial | ⚡ Quick win

Resolve the private_swiftui_state warning without breaking access.

SwiftLint reports private_swiftui_state on line 130. showingViewOptionsPopover is written from viewOptionsButton in WorkspaceListView+Toolbar.swift, so adding private or fileprivate will not compile. Choose one of these:

  • Move viewOptionsButton into this file and mark the property private.
  • Keep the property internal and add a targeted // swiftlint:disable:next private_swiftui_state with the cross-file reason.

The same rule was raised earlier for the removed showingComputerOrderSheet property.

🧰 Tools
🪛 SwiftLint (0.65.0)

[Warning] 130-130: SwiftUI state properties should be private

(private_swiftui_state)

🤖 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/WorkspaceListView.swift`
around lines 129 - 130, Resolve the private_swiftui_state warning for
showingViewOptionsPopover in WorkspaceListView without breaking its access from
viewOptionsButton in WorkspaceListView+Toolbar.swift: either move
viewOptionsButton into the same file and make the state private, or retain
internal access and add a targeted next-line SwiftLint suppression documenting
the cross-file usage.

Source: Linters/SAST tools

@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

Design update after dogfood feedback: sort moved out of the plain filter menu into a Mail-style view-options card (menu-styled popover) whose top row is three illustrated tiles, each a miniature rendering of what the mode does to the list (computer sections / rank-badged sections with drag grips / flat time-stamped rows) with radio checks. Selection re-sorts the list live behind the card; the computer-order editor presents from the card; read-state and machine filter rows share it. A UIMenu can only render text plus icon-sized images, hence a popover rather than a Menu. Also: the sort control now shows regardless of computer count (a wedged secondary-Mac connection previously hid it), and the order editor lists paired-but-offline computers so they keep their slot.

azooz2003-bit and others added 5 commits August 8, 2026 17:58
Drop the machines filter section (the title picker already owns computer
selection), make selecting Computer Order inert (the editor opens only
from the explicit Edit Computer Order row), inset the schematic rank
badges off the tile border, and use regular-weight selection checkmarks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The popover inherits the presenting toolbar button's font environment, so
rows rendered with toolbar weight; set body + regular at the card root.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
'Automatic' says nothing; 'Connected First' states the rule: the connected
computer leads, the rest follow by name. Raw value and persistence keep
the automatic spelling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
'Automatic'/'Connected First' mislabeled the rule and the alphabetical
tail matched no user model. The mode is now Last Opened: the connected
computer counts as opened now, the rest order by when this device last
used them (pairing lastSeenAt as the device-local record), never-opened
computers alphabetical last. Raw value and persistence keep 'automatic'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…seed

Cursor: the Last Opened order read pairedMacs.lastSeenAt but a pairing
refresh never rebuilt the derived list, so the aggregate order went stale
until the next workspace event; recompute on pairedMacs change (the
derivation already depended on pairedMacs for customization stamping).
Also seed the computer-order editor from the aggregated rows instead of
the filter-menu machine list, which empties below its two-machine floor
and would drop a singleton computer or mismatch the tail order.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 89c0545. Configure here.

id: representativeID,
macDeviceID: representativeID,
instanceTag: nil,
name: names[representativeID] ?? mac.resolvedName,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Order sheet stores pairing IDs

Medium Severity

computerOrderSheetMachines now assigns deviceRepresentativeID (a pairing id that can include an instance tag) to WorkspaceFilterMachine.macDeviceID. The order sheet persists that field as computer priority, which is documented and ranked as a physical Mac device id. Tagged builds therefore save unstable ids; after the preferred instance changes, alias expansion can miss and Computer Order stops applying for that Mac. The previous filterMachines path used the convenience initializer that strips the tag via pairingIdentity.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 89c0545. Configure here.

@azooz2003-bit
azooz2003-bit merged commit 0883e93 into main Aug 9, 2026
17 checks passed
@azooz2003-bit
azooz2003-bit deleted the feat-ios-all-computers-sort branch August 9, 2026 03:01
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