Repository navigation
feat(workbench): switch conversation and editor tabs by worktree - #1039
Merged
Merged
Conversation
Author
|
@xintaofei 辛苦看下这个 worktree 工作台界面的改动,可以把会话 tab 和 编辑器 tab 跟随所属的 worktree 进行隔离,左下角有一个工作台的开关来切换到隔离状态。 就我来说,因为 tab 分不出是哪一个项目/worktree,我很少通过 tab 来切换会话,一般都走侧边栏,这样 tab 和 编辑器都 worktree 隔离可以避免杂乱,误操作。 |
…nt across worktrees - Turning Workbench on keeps the current tab and per-group picks; only a worktree switch restores a remembered selection, and leaving the mode forgets them. - The active folder follows the active tab inside a scope, so a chat conversation keeps its hidden chat folder (chat-mode chrome, terminal); an empty scope still owns the folder chrome. - Closing the active tab focuses its neighbour among the worktree's own tabs and groups instead of jumping to the first tab. - A scope whose folder leaves the workspace moves to the parent repo, a remaining tab's worktree, or the first open folder. - The composer's folder picker moves its own draft (typed prompt and all) and the scope follows it once the retarget lands; "inherit from active" reads the tab the user is on before any scope switch. - The tab strip offers only on-screen groups as split targets.
The separate disclosure button exists only in Workbench mode, where the row button selects the worktree; in normal mode the row button stays the disclosure control with its inline chevron and explanatory comment.
…tate updaters - "Close others" / "close all" act on the worktree's references in one operation: buffers another worktree still holds only leave this scope, the rest close behind a single confirmation, and cancelling closes nothing. - Scope references of closed buffers are dropped after the removal commits (including suspended duplicates and dormant-profile duplicates), so a replayed updater can no longer orphan a buffer; the selection moves to the scope-order neighbour without flashing the first tab. - Restored browser tabs register their scope outside the updater. - An open aimed at another worktree no longer takes the current scope's selection through a shared browser tab; turning Workbench on keeps the file the user is looking at.
Choosing chat mode in the composer's folder picker now carries that draft (typed prompt and all) into the global scope, like a folder switch does, and a new chat inherits the agent of the tab the user is on rather than the global scope's selection.
…ving Workbench - Restored pages join their folder's scope after the merge commits, and any committed buffer that no scope references is adopted, so a page restored while a queued close removes its duplicate is never invisible. - Turning Workbench off keeps the file the scope was showing.
… View options The PR named its mode "Workbench", which the app already uses for the route surface (`WorkbenchRoute`). The mode makes a window's conversation and file tabs follow the selected folder, so the store, helpers, tests and stored preference now say that (`folder-tabs-store`, `isTabInScope`, `TabScope`, `workspace:tabs-follow-folder:*`). The switch leaves the status bar for the sidebar's View options menu, next to the other display choices, since the sidebar is where folders are selected while it is on.
…der again Three file-open callbacks defaulted their scope with a call in the parameter list (`scope = openingScope(...)`). The React Compiler cannot reorder that, so it skipped the whole `WorkspaceProvider`, and every compiler lint rule went quiet there. That is why two `set-state-in-effect` suppressions had started reporting as unused and were deleted. The default now runs in the function body, the provider is analyzed again, and both suppressions are back where they were.
The preference is stored per backend and read once, at hydration, so a window opened earlier kept the old mode until it was reloaded. Once a window has hydrated it now listens for the stored key to change and follows it, re-reading the key when the event arrives (a queued event may carry an older value) and keeping its own folder.
…e folder All folders shared one split tree, so a folder whose tabs filled only part of it lost its resize handles, and unsplit-all, dissolve and orientation changes reached into other folders' arrangements. Each tab view now has its own group state (layout, assignments, selection, tile flags): one for normal mode and one per folder. The view on screen lives in the store's group fields; a folder switch parks it in `groupViews` and loads the next. A folder's first view is the normal layout narrowed to its tabs under the same group ids, so turning the mode on moves no tab. Turning it off restores the normal layout. Hidden tabs keep rendering in their own view's group shell, and shells come in a fixed id order, so a folder switch never reparents or moves a live conversation. Folder views persist in the group blob under `views`. The top level stays the normal-mode view, and the views parked from the last session are dropped if the stored mode comes back off.
A draft moved by the composer's folder or chat-mode picker kept its prompt but could land beside the target folder's own draft, so the folder showed two "New Conversation" tabs. Turning the mode off did the same, putting every folder's drafts back into one group. The moved draft now closes the blank drafts sharing its group in its new folder, including when the user moved on before the move landed. Turning the mode off keeps one draft per group: the active one, else one with text, else the first. A draft whose composer holds text is never closed, so two drafts can remain but no prompt is lost.
While tabs follow the folder, selecting a folder with no conversation open left a blank column: no tab strip, no "+", and nothing to say which folder was on screen, since the sidebar marked it only with `aria-current`. The unsplit strip now stays up for an empty folder, with its new-conversation button (and no maximize, since there is nothing to maximize). The column shows which folder is empty and offers a new conversation there, or a new chat for the chat scope. Nothing is opened unasked, so visiting folders still collects no drafts. The folder on screen also gets the selected-row tint the conversation cards use.
…s split before its tabs load Review follow-ups to the folder views and draft tidying: - A draft counted as blank when it had no saved text, but the composer saves on a 300 ms debounce and never saves image attachments. Mounted composers now report unsaved content per draft key, and a draft with any is kept. The draft on screen is never closed either: the user may have switched to it while a moved draft was on its way. - A folder view projected before the tab set was known (the first snapshot failed) dropped the assignments of conversations not loaded yet, so their split collapsed when they arrived. The projection now keeps everything until the set is known, and the invariant pass narrows it.
The composer reported what it holds from an effect, after React committed it, and a dropped or pasted image counts only once it has been read. So a draft could look blank to the tab store's tidying for a moment after a file intake began, or for as long as an upload ran, and be closed with the file still on its way. The attachments hook now counts each intake (read, upload, native picker, clipboard read, OS drop) the moment it starts and calls the host's `onIntakeStart` synchronously. The composer marks its draft key as holding content right then, and clears that mark from its committed state once the last intake has settled.
Review follow-ups to the composer's intake reporting: - The context-menu paste (and its Ctrl/⌘+Shift+V shortcut) reads the clipboard before it hands any image to the counted intake, so a draft looked blank while that read was pending. The whole paste is now one intake, through the hook's new `beginIntake` for hosts. - An intake that starts and settles before React renders leaves `intakePending` false both times, so the composer's report never re-ran and the mark set at the start kept a blank draft protected for good. The hook now also bumps `intakeRevision` on every start and settle, and the composer re-reports on it.
Collaborator
|
codeg work task |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Title:
feat: add worktree-scoped Workbench modeSummary
Add an optional Workbench mode that switches conversation and editor tabs together when selecting a worktree folder.
This change is client-only. Server APIs, persistence schemas, and build configuration remain unchanged.
Screenshots
Validation