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>
This commit is contained in:
Sandeep Somavarapu
2026-03-11 15:25:41 +01:00
committed by GitHub
parent 39a834be39
commit a5cf4ddbfe
2 changed files with 58 additions and 15 deletions

View File

@@ -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<boolean>('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);

View File

@@ -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<IsolationMode>());
readonly onDidChange: Event<IsolationMode> = 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<IsolationMode>[] = [
{
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));
}
}
}