Skip to content

cloud tree: workspace rows derive the unread dot from their terminals - #12301

Open
lawrencecchen wants to merge 1 commit into
mainfrom
feat-cloud-unread-derived
Open

cloud tree: workspace rows derive the unread dot from their terminals#12301
lawrencecchen wants to merge 1 commit into
mainfrom
feat-cloud-unread-derived

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

The blue unread dot from #12112 sat on terminal rows only, so a collapsed workspace in the right sidebar hid it.

CloudTreeNode.hasUnreadNotification is computed on every read from the terminal rows beneath a node (no stored flag on workspace or machine rows), and the workspace and local-workspace rows render the same CloudTreeUnreadDot the terminal rows use. The dot stays in the layout with opacity toggled, so the in-place row refresh repaints it. New string cloudTree.workspace.unread.help (en, ja).

Test: CloudTreeOneMachineManyWorkspacesTests/workspaceUnreadDerivesFromItsTerminals (unread on one terminal marks only its workspace and the machine; reading clears both; adopt(from:) carries the derived value). Hosted run: https://github.com/manaflow-ai/cmux/actions/runs/34556707400 (success).


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
UI-only cloud sidebar indicator with derived state and a focused unit test; terminal unread storage is unchanged.

Overview
Workspace rows in the cloud tree now show the same blue unread attention dot as terminal rows, so a collapsed workspace still signals unread terminal notifications on this Mac (previously the dot lived only on terminal rows).

CloudTreeNode.hasUnreadNotification is computed on read from terminal hasUnreadNotification flags under each node—no separate stored state on workspace or machine rows. CloudTreeCellView passes that into CloudTreeRowContentView as hasUnreadDescendant for remote and local workspace rows.

Unread UI is centralized in CloudTreeUnreadDot (opacity toggling, help, accessibility); terminal rows use it instead of an inline circle. New copy cloudTree.workspace.unread.help (en/ja).

Test workspaceUnreadDerivesFromItsTerminals checks workspace/machine derivation, clearing on read, and adopt(from:).

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


Summary by cubic

Workspace rows now show the unread notification dot based on their terminal rows, so a collapsed workspace in the right sidebar no longer hides it. Previously only terminal rows had the dot; now CloudTreeNode.hasUnreadNotification is computed from descendant terminals on every read, and workspace rows use the same opacity-toggled CloudTreeUnreadDot as terminals, with a new help string for workspace unread state.

Written for commit d882e49. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added unread notification indicators to workspace and local workspace rows.
    • Unread status now propagates from terminals through their workspaces and machines.
    • Added English and Japanese help text explaining unread terminal notifications.
  • Bug Fixes

    • Improved consistency of unread indicators across terminal, workspace, and machine views.
    • Indicators now update correctly when notifications are read or refreshed.

The blue dot only sat on terminal rows, so a collapsed workspace in the
right sidebar hid it. CloudTreeNode.hasUnreadNotification is computed from
the terminal rows on every read (no stored flag on the workspace), and the
workspace and local-workspace rows render the same CloudTreeUnreadDot the
terminal rows use.

Claude-Session: https://claude.ai/code/session_015VUYpjo5ryiivbnAheYQXk
@vercel

vercel Bot commented Sep 11, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated
cmux166 Ready Ready Preview Sep 11, 2026 3:22am UTC
cmux41 Ready Ready Preview Sep 11, 2026 3:22am UTC

@github-actions

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 08b2d90d-4e41-4bbe-86ac-4859e43d9476

📥 Commits

Reviewing files that changed from the base of the PR and between 897bb7a and d882e49.

📒 Files selected for processing (5)
  • Resources/Localizable.xcstrings
  • Sources/Cloud/CloudTreeCellView.swift
  • Sources/Cloud/CloudTreeNode.swift
  • Sources/Cloud/CloudTreeRowContentView.swift
  • cmuxTests/CloudTreeOneMachineManyWorkspacesTests.swift

Included review availability: Your plan provides up to 10 included reviews per hour; 5 remain after this review.


📝 Walkthrough

Walkthrough

The change derives unread terminal notification state through the cloud tree and displays a shared unread dot on workspace, local-workspace, and terminal rows. It adds localized workspace help text and regression coverage for propagation and clearing.

Changes

Unread notification indicators

Layer / File(s) Summary
Unread state derivation and coverage
Sources/Cloud/CloudTreeNode.swift, cmuxTests/CloudTreeOneMachineManyWorkspacesTests.swift
Cloud tree nodes derive unread state from terminal notifications. Tests cover workspace and machine propagation, clearing, and refreshed node adoption.
Workspace indicator rendering
Sources/Cloud/CloudTreeCellView.swift, Sources/Cloud/CloudTreeRowContentView.swift, Resources/Localizable.xcstrings
Row configuration passes derived unread state to row content. Workspace, local-workspace, and terminal rows use the shared unread dot with localized help text.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: austinywang

Merge Risk: ⚪ Minimal · up to d882e

Unread indicators are derived from terminal notification state and remain visible on collapsed workspace rows, with localized help text and regression coverage for propagation and clearing.


Important

Pre-merge checks failed

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

❌ Failed checks (2 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Algorithmic Complexity ❌ Error The PR adds a recursive full-collection scan in production row rendering. Sources/Cloud/CloudTreeNode.swift:81-83 evaluates children.contains { $0.hasUnreadNotification }, and the closure can recu… Compute unread state once while building each snapshot. Use the existing unread-terminal Set and a single post-order aggregation, or an index/dictionary keyed by node identity, then pass the precomputed result to row content. Do not recur…
Cmux Full Internationalization ❌ Error The PR adds the user-facing key cloudTree.workspace.unread.help through String(localized:defaultValue:), but its Resources/Localizable.xcstrings entry has translations only for en and ja. Th… Add non-placeholder translated stringUnit values for all 18 missing locale codes under cloudTree.workspace.unread.help in Resources/Localizable.xcstrings. Keep the existing localized Swift API and matching en and ja entries.
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 4 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (22 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: workspace rows derive the unread dot from terminal state.
Description check ✅ Passed The description clearly explains the problem, implementation, localization change, and regression test. It omits the template headings for Demo Video, Review Trigger, and Checklist, but the core requi…
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 production diff adds only a synchronous recursive getter to the existing non-Sendable CloudTreeNode reference type and passes its value through AppKit/SwiftUI row rendering. `CloudTreeRowContent…
Cmux Swift Blocking Runtime ✅ Passed PASS: The production diff adds only a computed unread-state property, a SwiftUI parameter, and a shared dot view. It adds no semaphore, blocking wait, sleep, delayed dispatch, polling loop, main-queue…
Cmux Browser Automation Off-Main ✅ Passed The review-scoped diff changes only localization, CloudTree UI/model code, and one CloudTree test. It does not change Sources/TerminalController.swift, ControlCommandExecutionPolicy.swift, browser…
Cmux Expensive Synchronous Load ✅ Passed PASS. The production changes only derive unread state by recursively checking the existing in-memory CloudTreeNode.children and pass that value to SwiftUI row content. They add no agent-history load…
Cmux Cache Substitution Correctness ✅ Passed PASS. The diff does not replace a fresh authoritative read in a persistence, history, undo, or snapshot path. It adds CloudTreeNode.hasUnreadNotification, which recursively derives a transient UI va…
Cmux No Hacky Sleeps ✅ Passed PASS. The authoritative diff changes only Resources/Localizable.xcstrings, Swift production files, and a Swift test file. It introduces no TypeScript, JavaScript, shell, or non-Swift runtime changes…
Cmux Swift Concurrency ✅ Passed The authoritative diff changes unread-state derivation, SwiftUI view composition, localization, and a regression test. Added-line inspection found no DispatchQueue, custom queue, DispatchGroup, Co…
Cmux Swift @Concurrent ✅ Passed PASS. The PR adds only synchronous Swift changes: a recursive CloudTreeNode.hasUnreadNotification property, synchronous CloudTreeCellView.configure usage, SwiftUI view properties/builders, and a s…
Cmux Swift Package Boundaries ✅ Passed No package-boundary failure is introduced. The diff adds a 9-line derived property to the existing CloudTreeNode outline model and uses it only to drive the CloudTree SwiftUI rows. The remaining pro…
Cmux Swiftpm Lockfiles ✅ Passed The review-scoped diff changes only localization, Cloud tree Swift sources, and a Cloud tree test. It does not change any Package.swift, Package.resolved, .gitignore, workflow, or Xcode project packag…
Cmux Swift Logging ✅ Passed PASS. The PR adds UI/state derivation and localization only. No added or changed lines contain print, debugPrint, dump, NSLog, ad hoc logging, Logger, or stdout/stderr diagnostics. The exist…
Cmux User-Facing Error Privacy ✅ Passed PASS. The production diff adds only unread-notification help text and related UI state. The English and Japanese strings say that a terminal has an unread notification on this Mac. They do not expose …
Cmux Swiftui State Layout ✅ Passed PASS. The SwiftUI diff adds only value inputs and a stateless CloudTreeUnreadDot view. It adds no ObservableObject, @Published, @StateObject, @EnvironmentObject, @ObservedObject, `@Bindabl…
Cmux Architecture Rethink ✅ Passed PASS. The diff adds no timing, blocking, polling, lock, observer, or side-channel repair path. CloudTreeNode.hasUnreadNotification is a computed traversal over existing terminal-row state. `CloudTre…
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS: The pull request does not add or materially change a standalone cmux-owned window. The authoritative diff changes CloudTree SwiftUI row views, CloudTreeNode state derivation, and a test. Added l…
Cmux Source Artifacts ✅ Passed PASS. The authoritative diff changes only five intentional paths: one localization catalog, three Swift product-source files, and one Swift test file. The patch adds source behavior, a localized strin…
Cmux No Test Or Debug Seam In Production Source ✅ Passed PASS. The production diff adds ordinary unread-state and SwiftUI presentation members: CloudTreeNode.hasUnreadNotification, CloudTreeRowContentView.hasUnreadDescendant, and CloudTreeUnreadDot. N…
Cmux No Ambient Global State ✅ Passed The production Swift diff adds no ambient global state. CloudTreeNode.hasUnreadNotification is an instance computed property on the constructable CloudTreeNode; CloudTreeUnreadDot is a construct…
Full details: Docstring Coverage

Explanation

Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 4 files. (1 skipped: 1 unsupported.)

Full details: Cmux Algorithmic Complexity

Explanation

The PR adds a recursive full-collection scan in production row rendering. Sources/Cloud/CloudTreeNode.swift:81-83 evaluates children.contains { $0.hasUnreadNotification }, and the closure can recursively scan each child subtree. Sources/Cloud/CloudTreeCellView.swift:57 evaluates this property during every row configuration. A full outline refresh configures all rows, so workspace and machine rows repeatedly traverse descendant workspace and terminal collections. These collections can contain about 1000 workspaces or terminal rows. The PR provides no cache, explicit bound, or measurement. The existing unread Set in LocalProjectionIndex shows that the source state is already indexed, but the new aggregate state is not computed once per snapshot.

Resolution

Compute unread state once while building each snapshot. Use the existing unread-terminal Set and a single post-order aggregation, or an index/dictionary keyed by node identity, then pass the precomputed result to row content. Do not recursively scan children from CloudTreeCellView.configure; alternatively add an invalidated cache with measurements if a recursive design is required.

Full details: Cmux Full Internationalization

Explanation

The PR adds the user-facing key cloudTree.workspace.unread.help through String(localized:defaultValue:), but its Resources/Localizable.xcstrings entry has translations only for en and ja. The touched catalog already contains 20 locale codes. The entry is missing ar, bs, da, de, es, fr, it, km, ko, nb, pl, pt-BR, ru, th, tr, uk, zh-Hans, and zh-Hant. This violates the rule requiring translated entries for every locale supported by the touched catalog.

  • Fix all pre-merge checks with AI
✨ 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-cloud-unread-derived

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.

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