Sessions: Unified project picker and target mode picker (#302375)

* Refactor NewChatWidget to use ProjectPicker for unified project selection

* Enhance project picker to migrate legacy storage for recently picked projects and last selected project

* Fix separator visibility for extension pickers in NewChatWidget toolbar

* Remove unused separator for extension pickers in NewChatWidget

* Enhance IsolationModePicker to support cloud mode and update visibility logic in NewChatWidget

* Refactor IsolationModePicker to TargetPicker and update related logic for session target selection

* Add padding to chat-full-welcome pickers container for improved layout

* Update hover styles for project picker action label to improve visibility

* Refactor project listing in ProjectPicker to deduplicate and sort projects by type

* Add extension toolbar pickers for remote sessions in NewChatWidget

* Add checked property to project items in ProjectPicker for selection indication

* Set repo URI from project picker on session initialization

* Update visibility of branch and sync indicators based on repository selection in NewChatWidget

* Update target mode labels in TargetPicker for clarity

* Improve styling of project picker button for better visibility

* fix: correct isolation option logic in TargetPicker initialization

* fix: update isolation option logic to treat false as disabled

* fix: add cancellation support for project selection in NewChatWidget

* fix: add fireEvent parameter to setSelectedFolder and setSelectedRepo methods in ProjectPicker

* Address PR feedback: fix trust revert, use GITHUB_REMOTE_FILE_SCHEME, fix setRepository behavior

- Fix trust denial to revert to previous project selection (folder or repo)
  instead of assuming previous URI is always a local folder
- Replace hardcoded 'github-remote-file' with GITHUB_REMOTE_FILE_SCHEME constant
- Keep worktree mode when repository is undefined (disable instead of switching)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR feedback on projectPicker.ts

- Rename storage keys to sessions.* namespace
- Remove repoId from IProjectSelection (URI encodes identity)
- Store URIs as UriComponents instead of strings
- Consolidate setSelectedFolder/setSelectedRepo into single setSelectedProject API
- Generalize removeFromRecents to work with any project URI
- Extract command string constants (COMMAND_BROWSE_FOLDERS/REPOS)
- Add legacy key migration for renamed storage keys

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR feedback: remove label from IProjectSelection, use IUriIdentityService

- Remove label from IProjectSelection; compute it internally via _getProjectLabel()
- Use IUriIdentityService for URI equality checks instead of string comparison
- Remove unused isEqual import

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Unify IsolationMode and TargetMode, replace setRepository with setProject

- Remove IsolationMode type; use TargetMode everywhere
- Replace isolationMode getter with isWorktree/isFolder/isCloud booleans
- Replace setRepository + setCloudMode with single setProject(ITargetPickerProject)
- Rename setPreferredIsolationMode → setPreferredMode, setIsolationMode → setMode
- Rename isolationMode field in draft state to targetMode
- Update newSession.ts to use TargetMode

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Extract ISessionProject to shared types file

- Create src/vs/sessions/contrib/sessions/common/types.ts with ISessionProject
- ISessionProject has kind, optional uri, optional repository — a global concept
- IProjectSelection (exported from projectPicker.ts) narrows it with required uri
- TargetPicker.setProject accepts ISessionProject (uri optional for state updates)
- Remove ITargetPickerProject — replaced by ISessionProject

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Refactor ISessionProject to SessionProject class

- Convert ISessionProject interface to SessionProject class with constructor(uri, repository?)
- Derive isFolder/isRepo from URI scheme instead of explicit kind field
- Add withRepository() for creating copies with updated repository
- Remove kind from IStoredProject and IDraftState (derived from URI)
- Update all consumers to use new SessionProject(uri) constructor

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Export GITHUB_REMOTE_FILE_SCHEME from sessionProject.ts, rename types.ts

- Rename types.ts → sessionProject.ts
- Export GITHUB_REMOTE_FILE_SCHEME from the common layer
- Update all imports across sessions codebase to use the new canonical location
- githubFileSystemProvider.ts now re-exports from sessionProject.ts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove important from project picker CSS

* Fix RemoteNewSession.targetMode to return 'cloud' instead of 'worktree'

* Remove label from IStoredProject, compute from URI on demand

* Remove setPreferredMode/setMode, use preferredMode parameter on setProject

* Remove GITHUB_REMOTE_FILE_SCHEME re-export from githubFileSystemProvider

* Remove unused setVisible from TargetPicker

* Add SessionProject to INewSession interface

- Add project property and setProject method to INewSession
- Implement in LocalNewSession and RemoteNewSession
- setRepoUri now delegates to setProject internally
- Update NewChatWidget to use setProject instead of setRepoUri

* Remove repoUri and setRepoUri from INewSession, use project instead

* Remove redundant target from draft state, derive from target picker

- Remove target (AgentSessionProviders) from IDraftState — redundant with targetMode
- Replace _currentTarget field with getter derived from _targetPicker.isCloud
- Simplify _onProjectSelected to use target picker state directly

* Unify session creation through _onProjectSelected

- _createNewSession is now a simple session factory (no trust handling)
- Initial session creation routes through _onProjectSelected when a
  project was restored, ensuring trust is handled consistently
- _onProjectSelected always creates a new session and sets the project
- Removes duplicate trust handling from _createNewSession

* Remove redundant repoUri change listener from _setNewSession

* Only store targetMode in draft state for local sessions

* Use session.project as source of truth instead of projectPicker.selectedProject

- Read project from _newSession.value?.project throughout the widget
- Update session project when repository is resolved in _openRepository
- _updateTargetPickerState prefers session project over picker selection
- Reduces coupling to the picker's internal state

* Pass SessionProject as parameter to _createNewSession

* Rename ModePicker.setRepository to reset()

* Remove redundant targetMode session listener

The branch picker visibility is already handled by TargetPicker.onDidChange.
Keep the disabled listener — needed for async extension-driven state changes.

* Only open repository for folder projects, not repos

* Clean up _openRepository: read session at resolve time, remove defensive fallbacks

* Fix URI.revive error for legacy string URIs in stored projects

Add _reviveUri helper that handles both UriComponents (new) and
plain string (legacy) formats from storage.

* Migrate string URIs to UriComponents on load, remove _reviveUri

Convert legacy string URI format to UriComponents during deserialization
and re-persist. All runtime code now uses URI.revive safely.

* Remove all legacy storage migration code from ProjectPicker

* Restore legacy folder/repo picker migration, only remove string→UriComponents migration

* Only recreate session when project type changes (folder↔repo)

* Revert: always create new session when project changes

* Pass project to _updateTargetPickerState to avoid stale session state

* Inline _updateTargetPickerState and remove method

* Force Folder mode for non-git projects, disable picker when no repo

* Fix target mode restore: use _createNewSession for restored projects

Don't route restored projects through _onProjectSelected — the target
picker was already correctly configured by _restoreState with the
preferred mode. Calling _onProjectSelected would re-call setProject
without the preferred mode, losing the restored state.

* Remove early return in setProject, always update trigger label

* Default to worktree on project change, simplify setProject

Remove _preferredLocalMode — target always resets to worktree when
a new folder with git is selected, forced to folder when no git.

* Route restored projects through _onProjectSelected, remove preferredMode

- Initial session creation always goes through _onProjectSelected
- Remove preferredMode parameter from TargetPicker.setProject
- Remove targetMode from IDraftState (derived from project)

* Restore targetMode from draft state via _openRepository preferredMode

Store targetMode in draft, pass it through _openRepository to
_targetPicker.setProject when the git repo resolves.

* Reset target mode only on user project change, retain on repo resolve

- setProject takes resetMode flag instead of preferredMode
- _onProjectSelected passes resetMode=true (user action → reset to worktree)
- _openRepository passes resetMode=false (repo resolving → keep current mode)
- Remove targetMode from draft state — no longer needed for restore
- Simplify _openRepository signature

* Fix resetMode: persist flag until repo resolves

When resetMode=true is passed but the project has no repo yet,
store _pendingReset so the mode resets to worktree when the
repo resolves in a subsequent setProject call.

* Simplify: never reset target mode on project change

Target mode is retained across project changes. Only forced transitions:
- repo → cloud
- folder without git → workspace
- cloud → folder with git → worktree (switching back from cloud)
User's explicit dropdown choice (worktree/folder) is always respected.

* Don't force workspace for non-git folders, keep current mode disabled

Only forced transitions: repo→cloud, cloud→folder=worktree.
Non-git folders show current mode as disabled until repo resolves.

* Show Folder mode for non-git folders when isolation option is enabled

* Default to worktree always for folder projects

* Refactor TargetPicker: extract _updateMode, simplify disabled state

- Extract mode logic into _updateMode(), called from setProject and config change
- Folder with git → worktree, folder without git → workspace, repo → cloud
- Picker only enabled when folder has git repo and isolation option is enabled

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Sandeep Somavarapu
2026-03-18 02:45:46 +01:00
committed by GitHub
parent 5d7e4c1646
commit ea5ef7532c
14 changed files with 765 additions and 819 deletions

View File

@@ -58,7 +58,7 @@ import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from '../../../../workbench/
import { IExtensionService } from '../../../../workbench/services/extensions/common/extensions.js';
import { IWorkbenchLayoutService } from '../../../../workbench/services/layout/browser/layoutService.js';
import { IActiveSessionItem, ISessionsManagementService } from '../../sessions/browser/sessionsManagementService.js';
import { GITHUB_REMOTE_FILE_SCHEME } from '../../fileTreeView/browser/githubFileSystemProvider.js';
import { GITHUB_REMOTE_FILE_SCHEME } from '../../sessions/common/sessionProject.js';
import { CodeReviewStateKind, getCodeReviewFilesFromSessionChanges, getCodeReviewVersion, ICodeReviewService, PRReviewStateKind } from '../../codeReview/browser/codeReviewService.js';
import { IGitRepository, IGitService } from '../../../../workbench/contrib/git/common/gitService.js';
import { IGitHubService } from '../../github/browser/githubService.js';