Repository navigation
iOS: quiet reconnecting UX — title-bar spinner, interactive terminal, no connection-driven pops #10821
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
iOS: quiet reconnecting UX — title-bar spinner, interactive terminal, no connection-driven pops #10821
Changes from 4 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
055f682
iOS: fix main-red compile in MobileWorkspaceAggregation
azooz2003-bit dab5c43
iOS: quiet reconnecting UX on the workspace detail screen
azooz2003-bit c7e292e
cli: fix main-red Encodable synthesis for PendingCursorShellApproval
azooz2003-bit 1bfa4cb
Merge remote-tracking branch 'origin/main' into feat-ios-reconnect-sp…
azooz2003-bit 6bcc8d2
iOS: fix second main-red from #10662 (fileprivate groupActionCapabili…
azooz2003-bit 35c8a42
iOS: gate terminal input on the effective (recovery-aware) status
azooz2003-bit 6c88986
iOS: disconnected state moves into the title bar too
azooz2003-bit File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/WorkspaceAbsenceAuthority.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| import CmuxMobileShellModel | ||
|
|
||
| /// Decides whether a workspace's absence from a freshly derived list is | ||
| /// authoritative — the workspace genuinely ceased to exist (deleted, closed, | ||
| /// or its Mac was unpaired/hidden) — or a transient hole opened by a degraded | ||
| /// connection (drop, redial, secondary-snapshot purge on foreground death). | ||
| /// | ||
| /// Selection and navigation may retarget or pop the mounted detail only on an | ||
| /// authoritative absence. A transient absence keeps the selection so the | ||
| /// detail's last-known snapshot stays mounted until the connection resolves; | ||
| /// the next healthy list then either restores the row or confirms the | ||
| /// deletion, which retargets normally. | ||
| enum WorkspaceAbsenceAuthority { | ||
| /// - Parameters: | ||
| /// - hasLastKnownRow: Whether the caller still holds the vanished | ||
| /// workspace's last-known row. Without one the owner cannot be | ||
| /// attributed, so only the foreground's health can gate the decision. | ||
| /// - rowIsForegroundServed: Whether that row is served by the | ||
| /// foreground RPC connection (device and build tag match the live or | ||
| /// recovering pairing). | ||
| /// - foregroundIsHealthy: Live foreground authority — connected with no | ||
| /// recovery in flight and no failed recovery. | ||
| /// - ownerStatus: The owning Mac's per-entry status, or `nil` when its | ||
| /// entry is gone entirely. A missing entry is an authoritative | ||
| /// removal (unpair/hide) when the foreground is healthy, and the | ||
| /// foreground-death purge of secondary snapshots otherwise. | ||
| static func absenceIsAuthoritative( | ||
| hasLastKnownRow: Bool, | ||
| rowIsForegroundServed: Bool, | ||
| foregroundIsHealthy: Bool, | ||
| ownerStatus: MobileMacConnectionStatus? | ||
| ) -> Bool { | ||
| guard hasLastKnownRow, !rowIsForegroundServed else { | ||
| return foregroundIsHealthy | ||
| } | ||
| guard let ownerStatus else { | ||
| return foregroundIsHealthy | ||
| } | ||
| return ownerStatus == .connected | ||
| } | ||
| } |
77 changes: 77 additions & 0 deletions
77
Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/WorkspaceAbsenceAuthorityTests.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| import CmuxMobileShellModel | ||
| import Testing | ||
| @testable import CmuxMobileShell | ||
|
|
||
| @Suite struct WorkspaceAbsenceAuthorityTests { | ||
| @Test func foregroundRowAbsenceIsAuthoritativeOnlyWhileHealthy() { | ||
| // Deleted while the foreground connection is live: retarget/pop. | ||
| #expect(WorkspaceAbsenceAuthority.absenceIsAuthoritative( | ||
| hasLastKnownRow: true, | ||
| rowIsForegroundServed: true, | ||
| foregroundIsHealthy: true, | ||
| ownerStatus: .connected | ||
| )) | ||
| // Vanished mid-recovery: a transient hole, hold the selection. | ||
| #expect(!WorkspaceAbsenceAuthority.absenceIsAuthoritative( | ||
| hasLastKnownRow: true, | ||
| rowIsForegroundServed: true, | ||
| foregroundIsHealthy: false, | ||
| ownerStatus: .connected | ||
| )) | ||
| } | ||
|
|
||
| @Test func secondaryRowAbsenceFollowsItsOwnEntryStatus() { | ||
| // A secondary Mac's live list omitted the workspace: deletion. | ||
| #expect(WorkspaceAbsenceAuthority.absenceIsAuthoritative( | ||
| hasLastKnownRow: true, | ||
| rowIsForegroundServed: false, | ||
| foregroundIsHealthy: false, | ||
| ownerStatus: .connected | ||
| )) | ||
| // The secondary went offline or is redialing: hold the selection. | ||
| #expect(!WorkspaceAbsenceAuthority.absenceIsAuthoritative( | ||
| hasLastKnownRow: true, | ||
| rowIsForegroundServed: false, | ||
| foregroundIsHealthy: true, | ||
| ownerStatus: .unavailable | ||
| )) | ||
| #expect(!WorkspaceAbsenceAuthority.absenceIsAuthoritative( | ||
| hasLastKnownRow: true, | ||
| rowIsForegroundServed: false, | ||
| foregroundIsHealthy: true, | ||
| ownerStatus: .reconnecting | ||
| )) | ||
| } | ||
|
|
||
| @Test func missingOwnerEntryIsAuthoritativeOnlyWhileForegroundIsHealthy() { | ||
| // Unpair/hide removes the entry while the shell is healthy: pop. | ||
| #expect(WorkspaceAbsenceAuthority.absenceIsAuthoritative( | ||
| hasLastKnownRow: true, | ||
| rowIsForegroundServed: false, | ||
| foregroundIsHealthy: true, | ||
| ownerStatus: nil | ||
| )) | ||
| // Foreground death purges secondary snapshots: hold the selection. | ||
| #expect(!WorkspaceAbsenceAuthority.absenceIsAuthoritative( | ||
| hasLastKnownRow: true, | ||
| rowIsForegroundServed: false, | ||
| foregroundIsHealthy: false, | ||
| ownerStatus: nil | ||
| )) | ||
| } | ||
|
|
||
| @Test func unknownRowFallsBackToForegroundHealth() { | ||
| #expect(WorkspaceAbsenceAuthority.absenceIsAuthoritative( | ||
| hasLastKnownRow: false, | ||
| rowIsForegroundServed: false, | ||
| foregroundIsHealthy: true, | ||
| ownerStatus: nil | ||
| )) | ||
| #expect(!WorkspaceAbsenceAuthority.absenceIsAuthoritative( | ||
| hasLastKnownRow: false, | ||
| rowIsForegroundServed: false, | ||
| foregroundIsHealthy: false, | ||
| ownerStatus: nil | ||
| )) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win
Consolidate the duplicated foreground-served check.
workspaceRowIsForegroundServed(Line 1548) duplicates the device/build comparison already implemented inselectedWorkspaceUsesForegroundConnection(Line 1513). The two differ only in how they treat a row whosemacDeviceIDequalsSelf.foregroundAnonymousKey: the new function treats it as foreground-served, the existing one does not.Extract one shared private helper that takes the row's
macDeviceIDandmacInstanceTagand returns whether it is foreground-served, then have both public/internal call sites use it. Keeping two independent implementations of the same correctness-critical fact risks future drift, even though today's normalization elsewhere makes the divergence unreachable.As per path instructions, "flag ... more than one disagreeing source of truth for the same fact" (
.github/review-bot-rules/reliability-single-source-of-truth.md).♻️ Suggested consolidation
🤖 Prompt for AI Agents