cmux-next: a Cloud workspace that is not connected shows why in its window and sidebar
Summary
Since #28358, a window keeps its Cloud workspaces when cmux Cloud is signed out, but it showed nothing useful for them: no sidebar row, and a window that held only Cloud workspaces kept its old content or an empty pane (review finding 6 of #28358; before #28358 that window closed). Now such a workspace shows as not connected, says why, and offers what brings it back.
Stacked on #28393 (which is stacked on #28358): the base is fix/pa-b7c-findings until those land.
- The state (
CloudWorkspaceAbsence, CmuxNextCloudUI): a window member on a Cloud machine that no machine lists now and that is not gone (WindowManager.isDead) is signed out (Sign In), Cloud off, paused (Resume Machine), or connecting.CloudWorkspaceAbsencesdecides it; the composition root builds it once behindCloudWorkspaceAbsenceHost(one-line forwards inAppServices+CloudAbsenceHost.swift), and windows and sidebars ask it. - The window shows a card in place of a blank pane: the workspace's name, "On ", why, and the button. A window that holds only such workspaces is presented (
hasMirroredWorkspacecounts a workspace that shows why), and the window invariant holds. While a workspace only connects and the window already shows content, the content stays (a redial never flashes). - The sidebar lists each kept workspace under its machine, with its last saved name and the reason as its second line, in the existing row style (dimmed as saved rows are, no close button). A machine with no section gets one with its saved name. A click shows it; close, drag and rename wait for the machine. Only in the window's default space: the space of a kept workspace is not saved yet (saving it with the account is P-AUSTIN B7d).
- Two variants (cmux-next-feature rule), one state model: the card (default) and a one-line form, only why and the button (Debug Settings
cloud.absentCompact). Lawrence picks one.
Owners: PL-switch (WindowController, window membership) and the sidebar owner a590 (CmuxNextSidebar/Model/SidebarSection+AbsentRows.swift, new rows). Sidebar owner a590: please give your words for the Sidebar-Look: trailer and the note in plans/cmux-next/sidebar-owner.md ("Disconnected Cloud workspace rows").
God files
Measured against b3670f4635a (#28393's head): WindowManager 1502 -> 1502 (moved out cloudAbsence 12 lines, absentContentDidAppear 7 lines and the makeController/WindowInvariants special cases; one changed line in hasMirroredWorkspace). Added: WindowController type +41 (mostly WindowController+CloudCreation.swift), SidebarBridge type +82 (SidebarBridge+Windows.swift), AppServices type +10, CaptureSceneRegistry.swift +47 (two capture scenes). CloudService unchanged. No App file is new except the Host conformance; the logic is in CmuxNextCloudUI and CmuxNextSidebar.
Testing
Focused command: scripts/ci/package-test-lane.sh suite Packages/macOS/CmuxNext CloudWorkspaceAbsentDisplayTests,CloudWorkspaceAccountListTests,CloudWorkspaceRestoreTests (fleet cmux-ci run).
Commits, in order:
c24282cb1e1red,56974631fbafix: neither compiled (a stub edit brokeCloudWorkspaceAbsence.swift; a tuple lost its labels). Kept, not rewritten; theirSidebar-Look: no visual changetrailers were wrong.24715e669aered (valid): compiles withCloudWorkspaceAbsence.init,.actionandWindowManager.cloudAbsencestubbed; also the one-line variant, the variant test and the capture scenes.ad4ad8e756bfix, withSidebar-Look: new disconnected rows under their machine, existing row styleand the sidebar-owner note.bd2a3eae236merge of #28393's branch.15f50ebe597refactor: the state moves out ofWindowManagerintoCloudWorkspaceAbsences. No behavior change.8fa31f8efadthe capture scenes seed saved names ("api-server" on "build-box").7cbebd27359What's New highlight.
- Compile-check
c7320e4eafac9f8d78b4072bat24715e669ae: passed. Compile-check713119c9a1ca4a7eb357934dat8fa31f8efad: passed. - Red
1dc7ef17646eef1ca1488e49at24715e669ae:CloudWorkspaceAbsentDisplayTestsfails with 16 issues on its assertions (the state, the shown card, the window waiting off screen, the row);aKeptWorkspaceRowGoesUnderItsMachineAndAMachineWithNoSectionGetsOnepasses there (it tests the sidebar helper, which the red did not stub: coverage). The other two suites pass. - Green
23376edabea15d23ccb135eeat8fa31f8efad: GREEN_RESULT
Observed / Not run
- Observed:
prepush-gate.pyadds no violations;localization_catalog.py checkonCloud.xcstringshas only the 8 parity errors the base catalog has (21 locales for every new string). - Not run: a live sign-out in a signed-in app (the tests and the capture use the account-state seam
WindowManager.cloudList, which #28398 replaces). The Sign In and Resume Machine buttons run the existing actions; no test clicks them. Austin's-day numbers: no sign-out in the scenario.
Changelog
Fixed: Signed out of cmux Cloud, your Cloud workspaces stay in their windows and sidebar and say why they are not connected, with Sign In or Resume Machine.
Proof
CAPTURE_PENDING
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
After signing out of cmux Cloud, a window keeps its Cloud workspaces but showed a blank pane or stale content for them. Each kept workspace now says why it is not connected and offers what brings it back. Stacked on #28393.
Behavior
- A shared state model distinguishes signed out (Sign In), Cloud off, machine paused (Resume Machine), and connecting.
- The window shows a card naming the workspace and its machine, or a one-line variant behind a Debug Settings toggle; a window holding only such workspaces is presented instead of waiting off screen.
- The sidebar lists each kept workspace under its machine with its saved name and the reason, in the window's default space only.