From 7f512c528d36154fe0cab63dcd75b505013fff44 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 19 Dec 2024 12:13:57 +0100 Subject: [PATCH] chat - fix setup in web based on remote connection --- .../chat/browser/actions/chatActions.ts | 19 ++++++++++++++----- .../contrib/chat/browser/chat.contribution.ts | 2 ++ .../contrib/chat/browser/chatSetup.ts | 10 ++++++++-- .../contrib/chat/common/chatContextKeys.ts | 4 ++++ .../electron-sandbox/chat.contribution.ts | 2 -- .../common/gettingStartedContent.ts | 7 +++---- 6 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts index a0bb888eb80..d1d7d951559 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts @@ -9,7 +9,7 @@ import { Codicon } from '../../../../../base/common/codicons.js'; import { fromNowByDay } from '../../../../../base/common/date.js'; import { Event } from '../../../../../base/common/event.js'; import { KeyCode, KeyMod } from '../../../../../base/common/keyCodes.js'; -import { Disposable, DisposableStore } from '../../../../../base/common/lifecycle.js'; +import { Disposable, DisposableStore, markAsSingleton } from '../../../../../base/common/lifecycle.js'; import { ThemeIcon } from '../../../../../base/common/themables.js'; import { URI } from '../../../../../base/common/uri.js'; import { ICodeEditor } from '../../../../../editor/browser/editorBrowser.js'; @@ -531,7 +531,10 @@ MenuRegistry.appendMenuItem(MenuId.CommandCenter, { submenu: MenuId.ChatCommandCenter, title: localize('title4', "Chat"), icon: Codicon.copilot, - when: ContextKeyExpr.has('config.chat.commandCenter.enabled'), + when: ContextKeyExpr.and( + ChatContextKeys.supported, + ContextKeyExpr.has('config.chat.commandCenter.enabled') + ), order: 10001, }); @@ -541,7 +544,10 @@ registerAction2(class ToggleCopilotControl extends ToggleTitleBarConfigAction { 'chat.commandCenter.enabled', localize('toggle.chatControl', 'Copilot Controls'), localize('toggle.chatControlsDescription', "Toggle visibility of the Copilot Controls in title bar"), 4, false, - ContextKeyExpr.has('config.window.commandCenter') + ContextKeyExpr.and( + ChatContextKeys.supported, + ContextKeyExpr.has('config.window.commandCenter') + ) ); } }); @@ -561,7 +567,7 @@ export class ChatCommandCenterRendering extends Disposable implements IWorkbench const contextKeySet = new Set([ChatContextKeys.Setup.signedOut.key]); - this._store.add(actionViewItemService.register(MenuId.CommandCenter, MenuId.ChatCommandCenter, (action, options) => { + const disposable = actionViewItemService.register(MenuId.CommandCenter, MenuId.ChatCommandCenter, (action, options) => { if (!(action instanceof SubmenuItemAction)) { return undefined; } @@ -607,6 +613,9 @@ export class ChatCommandCenterRendering extends Disposable implements IWorkbench agentService.onDidChangeAgents, chatQuotasService.onDidChangeQuotas, Event.filter(contextKeyService.onDidChangeContext, e => e.affectsSome(contextKeySet)) - ))); + )); + + // Reduces flicker a bit on reload/restart + markAsSingleton(disposable); } } diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index b03d4605d16..456c8817cd4 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -81,6 +81,7 @@ import { Extensions, IConfigurationMigrationRegistry } from '../../../common/con import { ChatEditorOverlayController } from './chatEditorOverlay.js'; import { ChatRelatedFilesContribution } from './contrib/chatInputRelatedFilesContrib.js'; import { ChatQuotasService, ChatQuotasStatusBarEntry, IChatQuotasService } from './chatQuotasService.js'; +import { ChatSetupContribution } from './chatSetup.js'; // Register configuration const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); @@ -316,6 +317,7 @@ registerWorkbenchContribution2(ChatEditorSaving.ID, ChatEditorSaving, WorkbenchP registerWorkbenchContribution2(ChatEditorAutoSaveDisabler.ID, ChatEditorAutoSaveDisabler, WorkbenchPhase.BlockRestore); registerWorkbenchContribution2(ChatViewsWelcomeHandler.ID, ChatViewsWelcomeHandler, WorkbenchPhase.BlockStartup); registerWorkbenchContribution2(ChatGettingStartedContribution.ID, ChatGettingStartedContribution, WorkbenchPhase.Eventually); +registerWorkbenchContribution2(ChatSetupContribution.ID, ChatSetupContribution, WorkbenchPhase.BlockRestore); registerWorkbenchContribution2(ChatQuotasStatusBarEntry.ID, ChatQuotasStatusBarEntry, WorkbenchPhase.Eventually); registerChatActions(); diff --git a/src/vs/workbench/contrib/chat/browser/chatSetup.ts b/src/vs/workbench/contrib/chat/browser/chatSetup.ts index 3e93dbf6375..53a86ec5245 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSetup.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSetup.ts @@ -58,6 +58,8 @@ import { IOpenerService } from '../../../../platform/opener/common/opener.js'; import { URI } from '../../../../base/common/uri.js'; import { IHostService } from '../../../services/host/browser/host.js'; import Severity from '../../../../base/common/severity.js'; +import { IWorkbenchEnvironmentService } from '../../../services/environment/common/environmentService.js'; +import { isWeb } from '../../../../base/common/platform.js'; const defaultChat = { extensionId: product.defaultChatAgent?.extensionId ?? '', @@ -106,11 +108,15 @@ export class ChatSetupContribution extends Disposable implements IWorkbenchContr constructor( @IProductService private readonly productService: IProductService, - @IInstantiationService private readonly instantiationService: IInstantiationService + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService ) { super(); - if (!this.productService.defaultChatAgent) { + if ( + !this.productService.defaultChatAgent || // needs product config + (isWeb && !this.environmentService.remoteAuthority) // only enabled locally or a remote backend + ) { return; } diff --git a/src/vs/workbench/contrib/chat/common/chatContextKeys.ts b/src/vs/workbench/contrib/chat/common/chatContextKeys.ts index f615233de50..be03126dd2d 100644 --- a/src/vs/workbench/contrib/chat/common/chatContextKeys.ts +++ b/src/vs/workbench/contrib/chat/common/chatContextKeys.ts @@ -5,6 +5,8 @@ import { localize } from '../../../../nls.js'; import { ContextKeyExpr, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; +import { IsWebContext } from '../../../../platform/contextkey/common/contextkeys.js'; +import { RemoteNameContext } from '../../../common/contextkeys.js'; import { ChatAgentLocation } from './chatAgents.js'; export namespace ChatContextKeys { @@ -27,7 +29,9 @@ export namespace ChatContextKeys { export const inChatInput = new RawContextKey('inChatInput', false, { type: 'boolean', description: localize('inInteractiveInput', "True when focus is in the chat input, false otherwise.") }); export const inChatSession = new RawContextKey('inChat', false, { type: 'boolean', description: localize('inChat', "True when focus is in the chat widget, false otherwise.") }); + export const supported = ContextKeyExpr.or(IsWebContext.toNegated(), RemoteNameContext.notEqualsTo('')); // supported on desktop and in web only with a remote connection export const enabled = new RawContextKey('chatIsEnabled', false, { type: 'boolean', description: localize('chatIsEnabled', "True when chat is enabled because a default chat participant is activated with an implementation.") }); + export const panelParticipantRegistered = new RawContextKey('chatPanelParticipantRegistered', false, { type: 'boolean', description: localize('chatParticipantRegistered', "True when a default chat participant is registered for the panel.") }); export const editingParticipantRegistered = new RawContextKey('chatEditingParticipantRegistered', false, { type: 'boolean', description: localize('chatEditingParticipantRegistered', "True when a default chat participant is registered for editing.") }); export const chatEditingCanUndo = new RawContextKey('chatEditingCanUndo', false, { type: 'boolean', description: localize('chatEditingCanUndo', "True when it is possible to undo an interaction in the editing panel.") }); diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts b/src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts index e71f4342b15..0e888b7f864 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/electron-sandbox/chat.contribution.ts @@ -6,7 +6,6 @@ import { InlineVoiceChatAction, QuickVoiceChatAction, StartVoiceChatAction, VoiceChatInChatViewAction, StopListeningAction, StopListeningAndSubmitAction, KeywordActivationContribution, InstallSpeechProviderForVoiceChatAction, HoldToVoiceChatInChatViewAction, ReadChatResponseAloud, StopReadAloud, StopReadChatItemAloud } from './actions/voiceChatActions.js'; import { registerAction2 } from '../../../../platform/actions/common/actions.js'; import { WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js'; -import { ChatSetupContribution } from '../browser/chatSetup.js'; registerAction2(StartVoiceChatAction); registerAction2(InstallSpeechProviderForVoiceChatAction); @@ -24,4 +23,3 @@ registerAction2(StopReadChatItemAloud); registerAction2(StopReadAloud); registerWorkbenchContribution2(KeywordActivationContribution.ID, KeywordActivationContribution, WorkbenchPhase.AfterRestored); -registerWorkbenchContribution2(ChatSetupContribution.ID, ChatSetupContribution, WorkbenchPhase.BlockRestore); diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts b/src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts index 7fd3e30163f..53c8ae80511 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts @@ -282,7 +282,6 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ // id: 'settings', // title: localize('gettingStarted.settings.title', "Tune your settings"), // description: localize('gettingStarted.settings.description.interpolated', "Customize every aspect of VS Code and your extensions to your liking. Commonly used settings are listed first to get you started.\n{0}", Button(localize('tweakSettings', "Open Settings"), 'command:toSide:workbench.action.openSettings')), - // when: '!config.chat.experimental.offerSetup', // media: { // type: 'svg', altText: 'VS Code Settings', path: 'settings.svg' // }, @@ -291,7 +290,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ // id: 'settingsSync', // title: localize('gettingStarted.settingsSync.title', "Sync settings across devices"), // description: localize('gettingStarted.settingsSync.description.interpolated', "Keep your essential customizations backed up and updated across all your devices.\n{0}", Button(localize('enableSync', "Backup and Sync Settings"), 'command:workbench.userDataSync.actions.turnOn')), - // when: '!config.chat.experimental.offerSetup && syncStatus != uninitialized', + // when: 'syncStatus != uninitialized', // completionEvents: ['onEvent:sync-enabled'], // media: { // type: 'svg', altText: 'The "Turn on Sync" entry in the settings gear menu.', path: 'settingsSync.svg' @@ -318,7 +317,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ // id: 'pickAFolderTask-Mac', // title: localize('gettingStarted.setup.OpenFolder.title', "Open up your code"), // description: localize('gettingStarted.setup.OpenFolder.description.interpolated', "You're all set to start coding. Open a project folder to get your files into VS Code.\n{0}", Button(localize('pickFolder', "Pick a Folder"), 'command:workbench.action.files.openFileFolder')), - // when: '!config.chat.experimental.offerSetup && isMac && workspaceFolderCount == 0', + // when: 'isMac && workspaceFolderCount == 0', // media: { // type: 'svg', altText: 'Explorer view showing buttons for opening folder and cloning repository.', path: 'openFolder.svg' // } @@ -327,7 +326,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ // id: 'pickAFolderTask-Other', // title: localize('gettingStarted.setup.OpenFolder.title', "Open up your code"), // description: localize('gettingStarted.setup.OpenFolder.description.interpolated', "You're all set to start coding. Open a project folder to get your files into VS Code.\n{0}", Button(localize('pickFolder', "Pick a Folder"), 'command:workbench.action.files.openFolder')), - // when: '!config.chat.experimental.offerSetup && !isMac && workspaceFolderCount == 0', + // when: '!isMac && workspaceFolderCount == 0', // media: { // type: 'svg', altText: 'Explorer view showing buttons for opening folder and cloning repository.', path: 'openFolder.svg' // }