From a5cf4ddbfef23dff75e36087893748bc6e0ae569 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 11 Mar 2026 15:25:41 +0100 Subject: [PATCH] Sessions: update new chat isolation picker behavior (#300791) * Sessions: reorder pickers, rename isolation labels, gate on config - Swap mode and model picker positions in toolbar - Move Default Approvals next to isolation mode picker with gap - Rename Folder/Worktree labels to Local/Copilot CLI - Gate isolation picker on github.copilot.chat.cli.isolationOption.enabled - Show picker as disabled (not hidden) when config is off - Add setEnabled API to IsolationModePicker - Listen for config changes and enforce worktree mode when disabled Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * revert * Update src/vs/sessions/contrib/chat/browser/newChatViewPane.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../contrib/chat/browser/newChatViewPane.ts | 39 ++++++++++++++++--- .../chat/browser/sessionTargetPicker.ts | 34 +++++++++++----- 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/vs/sessions/contrib/chat/browser/newChatViewPane.ts b/src/vs/sessions/contrib/chat/browser/newChatViewPane.ts index b5985a3766a..09e0deceaf5 100644 --- a/src/vs/sessions/contrib/chat/browser/newChatViewPane.ts +++ b/src/vs/sessions/contrib/chat/browser/newChatViewPane.ts @@ -211,7 +211,7 @@ class NewChatWidget extends Disposable implements IHistoryNavigationWidget { this._register(this._targetPicker.onDidChangeTarget((target) => { this._createNewSession(); const isLocal = target === AgentSessionProviders.Background; - this._isolationModePicker.setVisible(isLocal); + this._updateIsolationPickerVisibility(); this._permissionPicker.setVisible(isLocal); this._branchPicker.setVisible(isLocal); this._syncIndicator.setVisible(isLocal); @@ -275,6 +275,27 @@ class NewChatWidget extends Disposable implements IHistoryNavigationWidget { this._currentLanguageModel.read(reader); this._updateDraftState(); })); + + // When isolation option config changes, update picker visibility + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('github.copilot.chat.cli.isolationOption.enabled')) { + this._updateIsolationPickerVisibility(); + } + })); + } + + private get _isIsolationOptionEnabled(): boolean { + return this.configurationService.getValue('github.copilot.chat.cli.isolationOption.enabled') !== false; + } + + private _updateIsolationPickerVisibility(): void { + const isLocal = this._targetPicker.selectedTarget === AgentSessionProviders.Background; + const enabled = this._isIsolationOptionEnabled; + if (!enabled) { + this._isolationModePicker.setPreferredIsolationMode('worktree'); + } + this._isolationModePicker.setVisible(isLocal); + this._isolationModePicker.setEnabled(enabled); } // --- Rendering --- @@ -324,9 +345,9 @@ class NewChatWidget extends Disposable implements IHistoryNavigationWidget { // Set initial visibility based on default target and isolation mode const isLocal = this._targetPicker.selectedTarget === AgentSessionProviders.Background; - const isWorktree = this._isolationModePicker.isolationMode === 'worktree'; - this._isolationModePicker.setVisible(isLocal); + this._updateIsolationPickerVisibility(); this._permissionPicker.setVisible(isLocal); + const isWorktree = this._isolationModePicker.isolationMode === 'worktree'; this._branchPicker.setVisible(isLocal && isWorktree); this._syncIndicator.setVisible(isLocal && isWorktree); @@ -443,6 +464,7 @@ class NewChatWidget extends Disposable implements IHistoryNavigationWidget { this._updateInputLoadingState(); this._branchPicker.setRepository(undefined); this._isolationModePicker.setRepository(undefined); + this._updateIsolationPickerVisibility(); this._syncIndicator.setRepository(undefined); this._modePicker.setRepository(undefined); @@ -453,6 +475,7 @@ class NewChatWidget extends Disposable implements IHistoryNavigationWidget { this._repositoryLoading = false; this._updateInputLoadingState(); this._isolationModePicker.setRepository(repository); + this._updateIsolationPickerVisibility(); this._branchPicker.setRepository(repository); this._syncIndicator.setRepository(repository); this._modePicker.setRepository(repository); @@ -464,6 +487,7 @@ class NewChatWidget extends Disposable implements IHistoryNavigationWidget { this._repositoryLoading = false; this._updateInputLoadingState(); this._isolationModePicker.setRepository(undefined); + this._updateIsolationPickerVisibility(); this._branchPicker.setRepository(undefined); this._syncIndicator.setRepository(undefined); this._modePicker.setRepository(undefined); @@ -1121,8 +1145,13 @@ class NewChatWidget extends Disposable implements IHistoryNavigationWidget { } } if (draft.isolationMode) { - this._isolationModePicker.setPreferredIsolationMode(draft.isolationMode); - this._isolationModePicker.setIsolationMode(draft.isolationMode); + if (this._isIsolationOptionEnabled) { + this._isolationModePicker.setPreferredIsolationMode(draft.isolationMode); + this._isolationModePicker.setIsolationMode(draft.isolationMode); + } else { + this._isolationModePicker.setPreferredIsolationMode('worktree'); + this._isolationModePicker.setIsolationMode('worktree'); + } } if (draft.branch) { this._branchPicker.setPreferredBranch(draft.branch); diff --git a/src/vs/sessions/contrib/chat/browser/sessionTargetPicker.ts b/src/vs/sessions/contrib/chat/browser/sessionTargetPicker.ts index 68d175b8fbe..2406e26e0cd 100644 --- a/src/vs/sessions/contrib/chat/browser/sessionTargetPicker.ts +++ b/src/vs/sessions/contrib/chat/browser/sessionTargetPicker.ts @@ -138,6 +138,7 @@ export class IsolationModePicker extends Disposable { private _isolationMode: IsolationMode = 'worktree'; private _preferredIsolationMode: IsolationMode | undefined; private _repository: IGitRepository | undefined; + private _enabled: boolean = true; private readonly _onDidChange = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; @@ -225,23 +226,32 @@ export class IsolationModePicker extends Disposable { } } + /** + * Enables or disables the picker. When disabled, the picker is shown + * but cannot be interacted with. + */ + setEnabled(enabled: boolean): void { + this._enabled = enabled; + this._updateTriggerLabel(); + } + private _showPicker(): void { - if (!this._triggerElement || this.actionWidgetService.isVisible || !this._repository) { + if (!this._triggerElement || this.actionWidgetService.isVisible || !this._repository || !this._enabled) { return; } const items: IActionListItem[] = [ { kind: ActionListItemKind.Action, - label: localize('isolationMode.folder', "Folder"), - group: { title: '', icon: Codicon.folder }, - item: 'workspace', + label: localize('isolationMode.worktree', "Copilot CLI"), + group: { title: '', icon: Codicon.worktree }, + item: 'worktree', }, { kind: ActionListItemKind.Action, - label: localize('isolationMode.worktree', "Worktree"), - group: { title: '', icon: Codicon.worktree }, - item: 'worktree', + label: localize('isolationMode.folder', "Local"), + group: { title: '', icon: Codicon.folder }, + item: 'workspace', }, ]; @@ -286,15 +296,19 @@ export class IsolationModePicker extends Disposable { const isDisabled = !this._repository; const modeIcon = this._isolationMode === 'worktree' ? Codicon.worktree : Codicon.folder; const modeLabel = this._isolationMode === 'worktree' - ? localize('isolationMode.worktree', "Worktree") - : localize('isolationMode.folder', "Folder"); + ? localize('isolationMode.worktree', "Copilot CLI") + : localize('isolationMode.folder', "Local"); dom.append(this._triggerElement, renderIcon(modeIcon)); const labelSpan = dom.append(this._triggerElement, dom.$('span.sessions-chat-dropdown-label')); labelSpan.textContent = modeLabel; dom.append(this._triggerElement, renderIcon(Codicon.chevronDown)); - this._slotElement?.classList.toggle('disabled', isDisabled); + this._slotElement?.classList.toggle('disabled', isDisabled || !this._enabled); + if (this._triggerElement) { + this._triggerElement.tabIndex = (!isDisabled && this._enabled) ? 0 : -1; + this._triggerElement.setAttribute('aria-disabled', String(isDisabled || !this._enabled)); + } } }