Skip to content

Apply sidebar workspace close/create as row edits instead of reloadData - #14866

Merged
teamleaderleo merged 2 commits into
mainfrom
fix/sidebar-row-edits-not-reload
Sep 27, 2026
Merged

teamleaderleo merged 2 commits into
mainfrom
fix/sidebar-row-edits-not-reload

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 26, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Any change to the AppKit sidebar's row id list that wasn't a small pure reorder went through reloadData, which retires every visible cell through tableView(_:didRemove:forRow:) → retirePresentation(commitEdits: true). Closing or creating a single workspace, whether from this window, the CLI, or an agent, therefore:

Change

SidebarWorkspaceTableRowEdit classifies a structural change as a pure removal or a pure insertion: the surviving rows keep their relative order, and ids are unique. Those changes now apply with removeRows / insertRows (no animation, inside the existing geometry-update serializer), then reconfigure the visible rows, since per-index state like shortcut digits and group counts shifts. Cells whose model is unchanged skip the repaint.

Mixed edits, reorders, forced reloads, duplicate ids, and the first population keep the existing paths. Group collapse and expand take the new path too, since they are pure drops and adds.

Tests

SidebarWorkspaceRowRetirementTests:

  • closingOneWorkspaceKeepsSurvivingRowCells mounts three rows, closes the middle one, and asserts the surviving rows keep the same cell instances.
  • rowEditClassifiesOnlyOrderPreservingDropsAndAdds covers removal, insertion, reorder, mixed edits, no-op, and duplicate ids.

The existing retirement tests, which remove the last row, now go through removeRows and still expect retirement via didRemove.

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


Summary by cubic

Applies sidebar workspace close/create (and group collapse/expand) as removeRows/insertRows edits instead of reloadData. Previously any structural change retired every visible cell, which committed rename and checklist drafts on unrelated rows early, closed their popovers, and repainted every row from a recycled cell.

  • Only order-preserving drops and adds take the new path; reorders, mixed edits, duplicate ids, and first population still reload.
  • Survivors keep their cell instances; then all loaded rows are reconfigured since per-index state like shortcut digits shifts. Reconfiguration now also covers rows NSTableView keeps prepared outside the viewport, which the existing animated-reorder path could leave stale.

Written for commit 2919ac8. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Sidebar workspace rows now update more smoothly when workspaces are added or closed. Unaffected rows remain in place instead of the entire list being refreshed, helping preserve their existing display state.
    • Reordered workspaces continue to use a separate update path, with loaded rows refreshed to reflect their new positions. Changes that combine additions and removals retain the existing update behavior.

Any change to the sidebar's row id list that wasn't a small pure reorder
went through reloadData, which retires every visible cell. Closing or
creating one workspace (in this window, from the CLI, or by an agent)
committed rename and checklist drafts early and closed popovers on
unrelated rows, and repainted every row from recycled cells.

When the next ids are the previous ids with rows only dropped or only
added (order preserved), apply them with removeRows/insertRows and
reconfigure the visible rows for per-index state. Mixed edits, reorders
with height changes, forced reloads, and duplicate ids keep the reload
path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

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

@coderabbitai

coderabbitai Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 23eb1db6-59ab-4b9f-aa05-911b68547fa5

📥 Commits

Reviewing files that changed from the base of the PR and between c55a8d4 and 2919ac8.

📒 Files selected for processing (1)
  • Sources/Sidebar/AppKitList/SidebarWorkspaceTableController.swift

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.


📝 Walkthrough

Walkthrough

The sidebar table now applies eligible order-preserving row additions and removals as incremental table updates. Reorder updates remain separate. Tests cover edit classification and preservation of surviving row cells.

Changes

Sidebar row updates

Layer / File(s) Summary
Classify row edits
Sources/Sidebar/AppKitList/SidebarWorkspaceTableRowEdit.swift, cmux.xcodeproj/project.pbxproj, cmuxTests/SidebarWorkspaceRowRetirementTests.swift
The helper identifies indexes for order-preserving additions or removals. The project includes the helper, and tests cover accepted and rejected edit cases.
Apply row edits
Sources/Sidebar/AppKitList/SidebarWorkspaceTableController.swift, cmuxTests/SidebarWorkspaceRowRetirementTests.swift
flushApply uses eligible edits to insert or remove affected rows and reconfigure loaded rows. A test checks that surviving cell instances remain in place.

Priority: ⬇️ Low

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

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant SidebarWorkspaceTableController
  participant SidebarWorkspaceTableRowEdit
  participant NSTableView
  SidebarWorkspaceTableController->>SidebarWorkspaceTableRowEdit: classify old and new row IDs
  SidebarWorkspaceTableRowEdit-->>SidebarWorkspaceTableController: return insertion or removal indexes
  SidebarWorkspaceTableController->>NSTableView: insert or remove affected rows
  SidebarWorkspaceTableController->>NSTableView: reconfigure loaded rows
Loading

Suggested reviewers: austinywang

Merge Risk: ⚪ Minimal · up to 2919a

The incremental sidebar updates refresh retained rows after each edit. No merge-blocking issue was established; the change is ready to merge subject to normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 2919a

The change is confined to sidebar presentation and preserves existing cleanup for removed rows. No new security boundary or authority is apparent, but the effects of externally initiated workspace changes and downstream draft commits are not fully established.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The directly changed behavior is bounded to AppKit sidebar row views and their drafts. CLI or agent workspace changes may trigger that presentation update, but their runtime caller paths were not independently mapped.

Trust Boundaries and Controls

  • inferred — No new trust or identity transition is shown in the changed row-edit path. The public-entrypoint classification attaches to the enclosing controller, while the changed update methods are private.

Resilience and Maintainability Implications

  • observed — Removal retains the established retirement and staged-commit mechanism, while surviving cells avoid that teardown. The eligibility check excludes mixed or reordered edits from the new path.

Important

Pre-merge checks failed

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

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
Cmux Swift Package Boundaries ❌ Error The diff adds SidebarWorkspaceTableRowEdit under the app target's root Sources/ tree. The type imports only Foundation, accepts generic Hashable IDs, and implements order-preserving insertion/… Extract SidebarWorkspaceTableRowEdit and its unit tests into a small SwiftPM target, for example CmuxSidebarModel under Packages/macOS/CmuxSidebarModel. Make SidebarWorkspaceTableRowEdit public, including its initializer and cases o…
Description check ⚠️ Warning The description clearly explains the problem, implementation, scope, and added tests. However, it does not state which test commands ran or their results, provides no required demo video or screenshot… Add the executed test commands and outcomes. Include a demo video or screenshot for this UI behavior change. Complete the applicable checklist items and document localization, documentation, and review status, or explain why each item does …
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 3 files. 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: applying sidebar workspace creation and closure as row edits instead of using reloadData.
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 Cloud Persistent Session And Early Input ✅ Passed PASS. The authoritative diff changes only sidebar workspace table row editing, Xcode project registration, and sidebar tests. It does not modify Cloud terminal creation, cmux-tui clients, transports, …
Cmux Swift Actor Isolation ✅ Passed No actor-isolation failure is introduced. The changed controller code remains inside the existing @MainActor SidebarWorkspaceTableController. SidebarWorkspaceTableRowEdit is an unannotated, pure…
Cmux Swift Blocking Runtime ✅ Passed The production diff adds row classification, AppKit row edits, and loaded-row reconfiguration. It adds no semaphore, blocking wait, sleep, delayed dispatch, polling loop, main-queue sync, or manual lo…
Cmux Browser Automation Off-Main ✅ Passed PASS: The PR changes only sidebar table controller, row-edit logic, project registration, and sidebar tests. The authoritative diff contains no browser socket commands, WebKit waits, worker-router cha…
Cmux Expensive Synchronous Load ✅ Passed The PR changes only sidebar row classification, NSTableView insert/remove/move updates, and loaded-row reconfiguration. The authoritative diff adds no RestorableAgentSessionIndex.load(), agent store…
Cmux Cache Substitution Correctness ✅ Passed The production diff changes sidebar table presentation only. It classifies row IDs and applies NSTableView removeRows/insertRows, then reconfigures loaded row views. It does not replace an autho…
Cmux No Hacky Sleeps ✅ Passed PASS. The pull request changes only Swift source/tests and an Xcode project file. It adds no TypeScript, JavaScript, shell, or runtime script changes. The added lines contain no fixed sleeps, delayed …
Cmux Algorithmic Complexity ✅ Passed The production changes use linear-time collection handling. SidebarWorkspaceTableRowEdit builds two Sets and performs one order-preserving subsequence scan; it does not rescan the row collection p…
Cmux Swift Concurrency ✅ Passed The PR adds synchronous row-edit classification and AppKit table updates. The changed production Swift lines add no DispatchQueue/DispatchGroup, Combine state, completion-handler API, or Task usage. T…
Cmux Swift @Concurrent ✅ Passed The Swift diff introduces no @concurrent or nonisolated async production code. The changed controller remains @MainActor, and flushApply, reconfigureLoadedRows, and the row-edit classifier a…
Cmux Swiftpm Lockfiles ✅ Passed The PR changes no Package.swift, Package.resolved, .gitignore, workflow, or dependency files. The cmux.xcodeproj/project.pbxproj changes only add SidebarWorkspaceTableRowEdit.swift as a sour…
Cmux Swift Logging ✅ Passed PASS: The pull request adds no prohibited logging. The added production Swift code only classifies row edits and reconfigures loaded rows. The diff adds no print, debugPrint, dump, NSLog, file…
Cmux User-Facing Error Privacy ✅ Passed PASS. The production diff changes sidebar table row classification, removeRows/insertRows updates, and loaded-row reconfiguration. It adds no user-facing errors, alerts, command output, API error …
Cmux Full Internationalization ✅ Passed The production diff adds row-edit logic and developer-only comments, but no user-facing Swift text, localization key, catalog entry, web message, metadata, or rendered content. The added tests and Xco…
Cmux Swiftui State Layout ✅ Passed The PR changes AppKit table-row behavior, adds a Foundation row-edit enum, project wiring, and AppKit tests. The changed lines add no SwiftUI state, GeometryReader, lazy/list row subtree, or render-ti…
Cmux Architecture Rethink ✅ Passed PASS. The diff adds a local, pure row-edit classifier and uses the existing MainActor table controller as the single owner of row state and table mutations. It introduces no timing workaround, polling…
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The changed production Swift code only updates sidebar table rows and adds a row-edit helper. It does not add or materially change an NSWindow, NSPanel, NSWindowController, SwiftUI Window, or WindowGr…
Cmux Source Artifacts ✅ Passed All four changed paths are intentional product source, test source, or Xcode project configuration. The new Swift source is registered in the project file and the added tests are durable test-system c…
Cmux No Test Or Debug Seam In Production Source ✅ Passed The production diff adds no test/debug seam. It adds the internal SidebarWorkspaceTableRowEdit used by SidebarWorkspaceTableController, and the private reconfigureLoadedRows helper has productio…
Full details: Description check

Explanation

The description clearly explains the problem, implementation, scope, and added tests. However, it does not state which test commands ran or their results, provides no required demo video or screenshot, and leaves required checklist items unresolved.

Resolution

Add the executed test commands and outcomes. Include a demo video or screenshot for this UI behavior change. Complete the applicable checklist items and document localization, documentation, and review status, or explain why each item does not apply.

Full details: Cmux Swift Package Boundaries

Explanation

The diff adds SidebarWorkspaceTableRowEdit under the app target's root Sources/ tree. The type imports only Foundation, accepts generic Hashable IDs, and implements order-preserving insertion/removal classification without AppKit, SwiftUI, Ghostty globals, or app lifecycle state. The new test exercises this logic independently of the table controller. This matches the rule's independently testable feature-logic condition. The controller changes themselves are AppKit glue and are allowed.

Resolution

Extract SidebarWorkspaceTableRowEdit and its unit tests into a small SwiftPM target, for example CmuxSidebarModel under Packages/macOS/CmuxSidebarModel. Make SidebarWorkspaceTableRowEdit public, including its initializer and cases or a public result API, and let the AppKit controller depend on that target. Keep SidebarWorkspaceTableController and AppKit cell reconfiguration in the app target.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

NSTableView keeps prepared row views outside the viewport and does not
ask viewFor again when they scroll in, so reconfiguring only visible rows
after removeRows/insertRows (and the existing moveRow path) could leave
them with a stale shortcut digit, first-row flag, or content.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo merged commit e34ab0a into main Sep 27, 2026
61 checks passed
@teamleaderleo
teamleaderleo deleted the fix/sidebar-row-edits-not-reload branch September 27, 2026 01:23
@github-actions

Copy link
Copy Markdown
Contributor

Merge receipt for 2919ac8242: every check was green at merge (16 verified; 14 skipped by policy). Full suite runs on main after merge.

teamleaderleo added a commit that referenced this pull request Sep 27, 2026
…idebar close fixes (#14885)

Pulls manaflow-ai/bonsplit#253 (strip-owned tab hover, Close Tab
accessibility action) and records the merged sidebar fixes #14826 and
#14866 under Unreleased.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
rustybret pushed a commit to rustybret/bmux that referenced this pull request Sep 27, 2026
8e27d37 Bump bonsplit for tab hover that follows the pointer; changelog for sidebar close fixes (manaflow-ai#14885)
5d24cf4 test: free hosted test terminals before the test returns (manaflow-ai#14886)
e34ab0a Apply sidebar workspace close/create as row edits instead of reloadData (manaflow-ai#14866)
ec763d5 Stop sidebar close buttons flashing on every row after a close (manaflow-ai#14826)
8f9c685 Restore legacy Subrouter Claude sessions through the proxy (manaflow-ai#14412)
7e2157e test: expect the Claude Teams restore preload to survive an unusable TMPDIR (manaflow-ai#14880)
f16e4e7 Fix prediction echo misses on sgr0 and bound keys, keep pinned-group windows on restore (manaflow-ai#14860)
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