diff --git a/src/vs/sessions/contrib/chat/browser/chat.contribution.ts b/src/vs/sessions/contrib/chat/browser/chat.contribution.ts index 9959c2f7ff4962..54ccec5e8d0d0c 100644 --- a/src/vs/sessions/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/sessions/contrib/chat/browser/chat.contribution.ts @@ -15,6 +15,9 @@ import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextke import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationRegistry } from '../../../../platform/configuration/common/configurationRegistry.js'; import { IFileDialogService } from '../../../../platform/dialogs/common/dialogs.js'; import { IQuickInputService, IQuickPickItem, QuickPickInput } from '../../../../platform/quickinput/common/quickInput.js'; +import product from '../../../../platform/product/common/product.js'; +import { Registry } from '../../../../platform/registry/common/platform.js'; +import { Extensions as WorkbenchConfigurationExtensions, IConfigurationMigrationRegistry } from '../../../../workbench/common/configuration.js'; import { registerWorkbenchContribution2, WorkbenchPhase } from '../../../../workbench/common/contributions.js'; import { ISessionsService } from '../../../services/sessions/browser/sessionsService.js'; import { ISessionsManagementService, inheritableSessionTarget } from '../../../services/sessions/common/sessionsManagement.js'; @@ -45,9 +48,8 @@ import { OpenSessionLinkOpenerContribution } from './openSessionLinkOpener.contr import { WorktreeCreatedTaskDispatcher, AGENT_HOST_RUN_WORKTREE_CREATED_TASKS_SETTING } from './worktreeCreatedTaskDispatcher.js'; import { AGENT_SESSIONS_SCOPED_INPUT_HISTORY_SETTING } from './sessionsChatHistory.js'; import '../../sessions/browser/mobile/mobileOverlayContribution.js'; -import { Registry } from '../../../../platform/registry/common/platform.js'; import { EditorAreaFocusContext, IsSessionsWindowContext, SideBarVisibleContext } from '../../../../workbench/common/contextkeys.js'; -import { NEW_SESSION_ACTION_ID } from '../common/constants.js'; +import { NEW_SESSION_ACTION_ID, UNIFIED_WORKSPACE_PICKER_SETTING } from '../common/constants.js'; import { SessionsChatBackgroundAvailableContext, SessionsChatBackgroundImageConfiguredContext, SessionsTitleBarNewSessionEnabledContext, SessionsWelcomeVisibleContext } from '../../../common/contextkeys.js'; import { Menus } from '../../../browser/menus.js'; import { ISessionsChatViewStateService, SessionsChatViewStateService } from './chatViewStateService.js'; @@ -55,6 +57,7 @@ import { SessionsChatResponseFileChangesService } from './sessionTurnChanges.js' import { IChatResponseFileChangesService } from '../../../../workbench/contrib/chat/browser/chatResponseFileChangesService.js'; import { SessionsChatPetAchievementContribution } from './chatPetAchievements.js'; import { AGENT_SESSIONS_CHAT_BACKGROUND_CODICONS_PRESET, AGENT_SESSIONS_PREFERRED_DARK_CHAT_BACKGROUND_IMAGE_LAYOUT_SETTING, AGENT_SESSIONS_PREFERRED_DARK_CHAT_BACKGROUND_IMAGE_SETTING, AGENT_SESSIONS_PREFERRED_LIGHT_CHAT_BACKGROUND_IMAGE_LAYOUT_SETTING, AGENT_SESSIONS_PREFERRED_LIGHT_CHAT_BACKGROUND_IMAGE_SETTING, chatBackgroundImageLayoutValues, ChatBackgroundImageLayout, ISessionsChatBackgroundService, SessionsChatBackgroundService } from '../../../services/chatBackground/browser/chatBackgroundService.js'; +import { LEGACY_UNIFIED_WORKSPACE_PICKER_SETTING, unifiedWorkspacePickerConfigurationMigration } from './unifiedWorkspacePickerConfiguration.js'; const CHANGE_AGENT_SESSIONS_CHAT_BACKGROUND_COMMAND_ID = 'workbench.action.chat.changeAgentSessionsBackground'; const CHANGE_AGENT_SESSIONS_CHAT_BACKGROUND_LAYOUT_COMMAND_ID = 'workbench.action.chat.changeAgentSessionsBackgroundLayout'; @@ -368,6 +371,20 @@ AccessibleViewRegistry.register(new SessionsChatAccessibilityHelp()); // register configuration Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ properties: { + [LEGACY_UNIFIED_WORKSPACE_PICKER_SETTING]: { + type: 'boolean', + default: product.quality !== 'stable', + scope: ConfigurationScope.APPLICATION, + deprecationMessage: localize('chat.agentSessions.consolidatedRemoteWorkspaces.deprecated', "Deprecated. Use the unified workspace picker setting instead."), + }, + [UNIFIED_WORKSPACE_PICKER_SETTING]: { + type: 'boolean', + default: product.quality !== 'stable', + scope: ConfigurationScope.APPLICATION, + description: localize('sessions.chat.unifiedWorkspacePicker.enabled', "Controls whether the Agents Window uses the unified workspace picker, which combines GitHub and remote workspaces, provides search, and, when supported, allows creating sessions with no workspace."), + tags: ['experimental'], + experiment: { mode: 'auto' }, + }, [AGENT_HOST_RUN_WORKTREE_CREATED_TASKS_SETTING]: { type: 'boolean', default: true, @@ -418,3 +435,5 @@ Registry.as(ConfigurationExtensions.Configuration).regis }, }, }); + +Registry.as(WorkbenchConfigurationExtensions.ConfigurationMigration).registerConfigurationMigrations([unifiedWorkspacePickerConfigurationMigration]); diff --git a/src/vs/sessions/contrib/chat/browser/newChatWidget.ts b/src/vs/sessions/contrib/chat/browser/newChatWidget.ts index 932b884e8763e1..a7ecb4d0bb547e 100644 --- a/src/vs/sessions/contrib/chat/browser/newChatWidget.ts +++ b/src/vs/sessions/contrib/chat/browser/newChatWidget.ts @@ -48,13 +48,14 @@ import { chatInputStackClass, ChatInputStackSlot, setChatInputStackSlot } from ' import { IChatPetService } from '../../../../workbench/contrib/chat/browser/chatPetService.js'; import { IChatTipService } from '../../../../workbench/contrib/chat/browser/chatTipService.js'; import { ChatContextKeys } from '../../../../workbench/contrib/chat/common/actions/chatContextKeys.js'; -import { ChatConfiguration, ChatModeKind } from '../../../../workbench/contrib/chat/common/constants.js'; +import { ChatModeKind } from '../../../../workbench/contrib/chat/common/constants.js'; import { IOpenerService } from '../../../../platform/opener/common/opener.js'; import { IStorageService, StorageScope } from '../../../../platform/storage/common/storage.js'; import { TOTAL_SESSIONS_KEY } from '../../sessions/browser/sessionsLifecycleTracker.js'; import { INewSessionComposerService, NewSessionWorkspacePreselectionSource } from './newSessionComposerService.js'; import { Menus } from '../../../browser/menus.js'; import { getAdditionalFolderContextId, getAdditionalRepositoryContextId } from '../common/newChatContextIds.js'; +import { UNIFIED_WORKSPACE_PICKER_SETTING } from '../common/constants.js'; // #region --- New Chat Widget --- @@ -151,8 +152,8 @@ export class NewChatWidget extends Disposable { }); this._useConsolidatedRemoteWorkspaces = observableFromEvent( this, - Event.filter(this.configurationService.onDidChangeConfiguration, event => event.affectsConfiguration(ChatConfiguration.ConsolidatedRemoteWorkspaces)), - () => this.configurationService.getValue(ChatConfiguration.ConsolidatedRemoteWorkspaces), + Event.filter(this.configurationService.onDidChangeConfiguration, event => event.affectsConfiguration(UNIFIED_WORKSPACE_PICKER_SETTING)), + () => this.configurationService.getValue(UNIFIED_WORKSPACE_PICKER_SETTING), ); this._isWorkspacePickerQuickChat = derived(this, reader => { const session = this._session.read(reader); diff --git a/src/vs/sessions/contrib/chat/browser/sessionWorkspacePicker.ts b/src/vs/sessions/contrib/chat/browser/sessionWorkspacePicker.ts index b031b495829044..533d622f207cfa 100644 --- a/src/vs/sessions/contrib/chat/browser/sessionWorkspacePicker.ts +++ b/src/vs/sessions/contrib/chat/browser/sessionWorkspacePicker.ts @@ -47,15 +47,13 @@ import { markOnboardingTarget } from '../../../../workbench/contrib/onboarding/b import { NewSessionWorkspacePreselectionSource } from './newSessionComposerService.js'; import { type IResolvedFolderWorkspace, SessionWorkspaceFallback } from './sessionWorkspaceFallback.js'; import { IChatRequestVariableEntry } from '../../../../workbench/contrib/chat/common/attachments/chatVariableEntries.js'; -import { ChatConfiguration } from '../../../../workbench/contrib/chat/common/constants.js'; import { ADDITIONAL_FOLDER_CONTEXT_ID_PREFIX, ADDITIONAL_REPOSITORY_CONTEXT_ID_PREFIX, getAdditionalFolderContextId, getAdditionalRepositoryContextId } from '../common/newChatContextIds.js'; +import { UNIFIED_WORKSPACE_PICKER_SETTING } from '../common/constants.js'; export type { IResolvedFolderWorkspace } from './sessionWorkspaceFallback.js'; const FILTER_THRESHOLD = 10; -export const AGENT_SESSIONS_CONSOLIDATED_REMOTE_WORKSPACES_SETTING = ChatConfiguration.ConsolidatedRemoteWorkspaces; - /** * Fixed picker width when the categorical tab bar is shown. Keeps the tab * row and the list aligned and prevents horizontal jitter when switching @@ -1254,7 +1252,7 @@ export class WorkspacePicker extends Disposable { } protected _useConsolidatedRemoteWorkspaces(): boolean { - return this.configurationService.getValue(AGENT_SESSIONS_CONSOLIDATED_REMOTE_WORKSPACES_SETTING); + return this.configurationService.getValue(UNIFIED_WORKSPACE_PICKER_SETTING); } private _getTabGroup(group: string | undefined): string | undefined { diff --git a/src/vs/sessions/contrib/chat/browser/unifiedWorkspacePickerConfiguration.ts b/src/vs/sessions/contrib/chat/browser/unifiedWorkspacePickerConfiguration.ts new file mode 100644 index 00000000000000..0700a988a9d1fb --- /dev/null +++ b/src/vs/sessions/contrib/chat/browser/unifiedWorkspacePickerConfiguration.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ConfigurationKeyValuePairs, ConfigurationMigration } from '../../../../workbench/common/configuration.js'; +import { UNIFIED_WORKSPACE_PICKER_SETTING } from '../common/constants.js'; + +export const LEGACY_UNIFIED_WORKSPACE_PICKER_SETTING = 'chat.agentSessions.consolidatedRemoteWorkspaces'; + +export const unifiedWorkspacePickerConfigurationMigration: ConfigurationMigration = { + key: LEGACY_UNIFIED_WORKSPACE_PICKER_SETTING, + includeApplication: true, + migrateFn: (value, accessor) => { + const pairs: ConfigurationKeyValuePairs = [[LEGACY_UNIFIED_WORKSPACE_PICKER_SETTING, { value: undefined }]]; + if (accessor(UNIFIED_WORKSPACE_PICKER_SETTING) === undefined) { + pairs.push([UNIFIED_WORKSPACE_PICKER_SETTING, { value }]); + } + return pairs; + }, +}; diff --git a/src/vs/sessions/contrib/chat/common/constants.ts b/src/vs/sessions/contrib/chat/common/constants.ts index 84a4e7e035871e..f7e9856c5e3dfb 100644 --- a/src/vs/sessions/contrib/chat/common/constants.ts +++ b/src/vs/sessions/contrib/chat/common/constants.ts @@ -4,3 +4,4 @@ *--------------------------------------------------------------------------------------------*/ export const NEW_SESSION_ACTION_ID = 'workbench.action.sessions.newChat'; +export const UNIFIED_WORKSPACE_PICKER_SETTING = 'sessions.chat.unifiedWorkspacePicker.enabled'; diff --git a/src/vs/sessions/contrib/chat/test/browser/sessionWorkspacePicker.test.ts b/src/vs/sessions/contrib/chat/test/browser/sessionWorkspacePicker.test.ts index 3a0e71708260b2..f26e533fc2a797 100644 --- a/src/vs/sessions/contrib/chat/test/browser/sessionWorkspacePicker.test.ts +++ b/src/vs/sessions/contrib/chat/test/browser/sessionWorkspacePicker.test.ts @@ -34,7 +34,8 @@ import { ISendRequestOptions, ISessionChangeEvent, ISessionsProvider } from '../ import { AgentHostFilterConnectionStatus, IAgentHostFilterEntry } from '../../../../services/agentHostFilter/common/agentHostFilter.js'; import { IAgentHostSessionsProvider } from '../../../../common/agentHostSessionsProvider.js'; import { ISession, ISessionWorkspace, ISessionWorkspaceBrowseAction, SessionStatus, SESSION_WORKSPACE_GROUP_GITHUB, SESSION_WORKSPACE_GROUP_LOCAL, SESSION_WORKSPACE_GROUP_REMOTE } from '../../../../services/sessions/common/session.js'; -import { AGENT_SESSIONS_CONSOLIDATED_REMOTE_WORKSPACES_SETTING, IWorkspacePickerItem, IWorkspacePickerOptions, WorkspacePicker } from '../../browser/sessionWorkspacePicker.js'; +import { IWorkspacePickerItem, IWorkspacePickerOptions, WorkspacePicker } from '../../browser/sessionWorkspacePicker.js'; +import { UNIFIED_WORKSPACE_PICKER_SETTING } from '../../common/constants.js'; import { WebWorkspacePicker } from '../../browser/webWorkspacePicker.js'; import { NewSessionWorkspacePreselectionSource } from '../../browser/newSessionComposerService.js'; import { ISessionsRecentWorkspacesService, SessionsRecentWorkspacesService } from '../../../../services/sessions/browser/sessionsRecentWorkspacesService.js'; @@ -3050,7 +3051,7 @@ function createTestablePicker( instantiationService.stub(IOutputService, {}); instantiationService.stub(IConfigurationService, new TestConfigurationService({ [RemoteAgentHostsEnabledSettingId]: remoteAgentHostsEnabled, - [AGENT_SESSIONS_CONSOLIDATED_REMOTE_WORKSPACES_SETTING]: consolidatedRemoteWorkspaces, + [UNIFIED_WORKSPACE_PICKER_SETTING]: consolidatedRemoteWorkspaces, })); instantiationService.stub(ICommandService, commandService); instantiationService.stub(IFileDialogService, {}); diff --git a/src/vs/sessions/contrib/chat/test/browser/unifiedWorkspacePickerConfiguration.test.ts b/src/vs/sessions/contrib/chat/test/browser/unifiedWorkspacePickerConfiguration.test.ts new file mode 100644 index 00000000000000..ae9cbd04a73f12 --- /dev/null +++ b/src/vs/sessions/contrib/chat/test/browser/unifiedWorkspacePickerConfiguration.test.ts @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; +import { LEGACY_UNIFIED_WORKSPACE_PICKER_SETTING, unifiedWorkspacePickerConfigurationMigration } from '../../browser/unifiedWorkspacePickerConfiguration.js'; +import { UNIFIED_WORKSPACE_PICKER_SETTING } from '../../common/constants.js'; + +suite('UnifiedWorkspacePickerConfiguration', () => { + + ensureNoDisposablesAreLeakedInTestSuite(); + + test('migrates application values without overwriting the new setting', async () => { + const copiedValue = await unifiedWorkspacePickerConfigurationMigration.migrateFn(true, () => undefined); + const preservedValue = await unifiedWorkspacePickerConfigurationMigration.migrateFn(false, key => key === UNIFIED_WORKSPACE_PICKER_SETTING ? true : undefined); + + assert.deepStrictEqual({ + key: unifiedWorkspacePickerConfigurationMigration.key, + includeApplication: unifiedWorkspacePickerConfigurationMigration.includeApplication, + copiedValue, + preservedValue, + }, { + key: LEGACY_UNIFIED_WORKSPACE_PICKER_SETTING, + includeApplication: true, + copiedValue: [ + [LEGACY_UNIFIED_WORKSPACE_PICKER_SETTING, { value: undefined }], + [UNIFIED_WORKSPACE_PICKER_SETTING, { value: true }], + ], + preservedValue: [ + [LEGACY_UNIFIED_WORKSPACE_PICKER_SETTING, { value: undefined }], + ], + }); + }); +}); diff --git a/src/vs/sessions/contrib/sessions/browser/views/sessionsViewActions.ts b/src/vs/sessions/contrib/sessions/browser/views/sessionsViewActions.ts index c3d3addd43b0e7..08dd2763c59f7a 100644 --- a/src/vs/sessions/contrib/sessions/browser/views/sessionsViewActions.ts +++ b/src/vs/sessions/contrib/sessions/browser/views/sessionsViewActions.ts @@ -43,8 +43,8 @@ import { registerExternalSessionsFilterMenu } from '../../../../../workbench/con import { ICustomViewService } from '../../../../services/customView/browser/customViewService.js'; import { IAutomationService } from '../../../../../workbench/contrib/chat/common/automations/automationService.js'; import { ChatAutomationsEnabledContext } from '../../../../../workbench/contrib/chat/common/automations/automationsEnabled.js'; -import { ChatConfiguration } from '../../../../../workbench/contrib/chat/common/constants.js'; import { AUTOMATIONS_CUSTOM_VIEW_ID } from '../automationsConstants.js'; +import { UNIFIED_WORKSPACE_PICKER_SETTING } from '../../../chat/common/constants.js'; const CLOSE_SESSION_COMMAND_ID = 'sessionsViewPane.closeSession'; registerAction2(class CloseSessionAction extends Action2 { @@ -546,7 +546,7 @@ registerAction2(class NewQuickChatAction extends Action2 { const sessionsService = accessor.get(ISessionsService); const sessionsPartService = accessor.get(ISessionsPartService); let activeSession; - if (accessor.get(IConfigurationService).getValue(ChatConfiguration.ConsolidatedRemoteWorkspaces)) { + if (accessor.get(IConfigurationService).getValue(UNIFIED_WORKSPACE_PICKER_SETTING)) { if (accessor.get(ISessionsManagementService).isQuickChatTargetAvailable()) { sessionsService.unsetNewSession(); sessionsPartService.getSessionView(undefined)?.selectNoWorkspace(); diff --git a/src/vs/sessions/contrib/sessions/test/browser/sessionsActions.test.ts b/src/vs/sessions/contrib/sessions/test/browser/sessionsActions.test.ts index 43dae57738e8b0..094ec49a36448d 100644 --- a/src/vs/sessions/contrib/sessions/test/browser/sessionsActions.test.ts +++ b/src/vs/sessions/contrib/sessions/test/browser/sessionsActions.test.ts @@ -13,7 +13,6 @@ import { IConfigurationService } from '../../../../../platform/configuration/com import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js'; import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js'; import { workbenchInstantiationService } from '../../../../../workbench/test/browser/workbenchTestServices.js'; -import { ChatConfiguration } from '../../../../../workbench/contrib/chat/common/constants.js'; import { Menus } from '../../../../browser/menus.js'; import { SESSION_CONVERSATION_SIDE_CHATS_GROUP } from '../../../../browser/sessionConversationGroups.js'; import { SessionView } from '../../../../browser/parts/sessionView.js'; @@ -26,6 +25,7 @@ import { mock, upcastPartial } from '../../../../../base/test/common/mock.js'; import { SessionConversationActionsContribution } from '../../browser/sessionsActions.js'; import '../../browser/views/sessionsViewActions.js'; import { createTestSession } from './sessionsListTestUtils.js'; +import { UNIFIED_WORKSPACE_PICKER_SETTING } from '../../../chat/common/constants.js'; suite('Sessions - Actions', () => { @@ -136,7 +136,7 @@ suite('Sessions - Actions', () => { let focusedSessionId: string | undefined; instantiationService.stub(IConfigurationService, new TestConfigurationService({ - [ChatConfiguration.ConsolidatedRemoteWorkspaces]: consolidatedRemoteWorkspaces, + [UNIFIED_WORKSPACE_PICKER_SETTING]: consolidatedRemoteWorkspaces, })); instantiationService.stub(ISessionsManagementService, new class extends mock() { override isQuickChatTargetAvailable(): boolean { diff --git a/src/vs/workbench/contrib/chat/browser/chat.shared.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.shared.contribution.ts index a4188451e6587e..fadf6af63c2c6d 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.shared.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.shared.contribution.ts @@ -482,14 +482,6 @@ configurationRegistry.registerConfiguration({ experiment: { mode: 'auto' }, agentHost: { key: AgentHostShowExternalSessionsConfigKey }, }, - [ChatConfiguration.ConsolidatedRemoteWorkspaces]: { - type: 'boolean', - default: product.quality !== 'stable', - scope: ConfigurationScope.APPLICATION, - description: nls.localize('chat.agentSessions.consolidatedRemoteWorkspaces', "Controls whether GitHub and remote workspaces are combined under Remote in the Agents Window workspace picker, with search always available and, when supported, a No workspace option."), - tags: ['experimental'], - experiment: { mode: 'auto' }, - }, [ChatConfiguration.SaveBeforeSend]: { type: 'boolean', description: nls.localize('chat.saveBeforeSend', "Controls whether all dirty editors except untitled editors are saved before sending a chat message."), diff --git a/src/vs/workbench/contrib/chat/common/constants.ts b/src/vs/workbench/contrib/chat/common/constants.ts index 2261a639012ebb..81433eaaae286b 100644 --- a/src/vs/workbench/contrib/chat/common/constants.ts +++ b/src/vs/workbench/contrib/chat/common/constants.ts @@ -53,7 +53,6 @@ export enum ChatConfiguration { AgentSessionProjectionEnabled = 'chat.agentSessionProjection.enabled', MigrateLegacyCopilotCliSessions = 'chat.agentSessions.migrateLegacyCopilotCli', ShowExternalAgentSessions = 'chat.agentSessions.showExternal', - ConsolidatedRemoteWorkspaces = 'chat.agentSessions.consolidatedRemoteWorkspaces', ExtensionToolsEnabled = 'chat.extensionTools.enabled', RepoInfoEnabled = 'chat.repoInfo.enabled', EditRequests = 'chat.editRequests',