diff --git a/src/vs/workbench/contrib/chat/browser/chatSetup.ts b/src/vs/workbench/contrib/chat/browser/chatSetup.ts index c0c4a49447e89..7189ecfdf0b85 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSetup.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSetup.ts @@ -35,7 +35,7 @@ import { defaultButtonStyles } from '../../../../platform/theme/browser/defaultS import { IWorkbenchContribution } from '../../../common/contributions.js'; import { IViewDescriptorService, ViewContainerLocation } from '../../../common/views.js'; import { IActivityService, ProgressBadge } from '../../../services/activity/common/activity.js'; -import { AuthenticationSession, IAuthenticationExtensionsService, IAuthenticationService } from '../../../services/authentication/common/authentication.js'; +import { AuthenticationSession, IAuthenticationService } from '../../../services/authentication/common/authentication.js'; import { IWorkbenchLayoutService, Parts } from '../../../services/layout/browser/layoutService.js'; import { IViewsService } from '../../../services/views/common/viewsService.js'; import { IExtensionsWorkbenchService } from '../../extensions/common/extensions.js'; @@ -325,7 +325,6 @@ class ChatSetupController extends Disposable { private readonly requests: ChatSetupRequests, @ITelemetryService private readonly telemetryService: ITelemetryService, @IAuthenticationService private readonly authenticationService: IAuthenticationService, - @IAuthenticationExtensionsService private readonly authenticationExtensionsService: IAuthenticationExtensionsService, @IViewsService private readonly viewsService: IViewsService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IProductService private readonly productService: IProductService, @@ -431,12 +430,7 @@ class ChatSetupController extends Disposable { try { showCopilotView(this.viewsService, this.layoutService); - session = await this.authenticationService.createSession(providerId, defaultChat.providerScopes[0]); - - this.authenticationExtensionsService.updateAccountPreference(defaultChat.extensionId, providerId, session.account); - this.authenticationExtensionsService.updateAccountPreference(defaultChat.chatExtensionId, providerId, session.account); - - entitlements = await this.requests.forceResolveEntitlement(session); + ({ session, entitlements } = await this.requests.signIn()); } catch (e) { this.logService.error(`[chat setup] signIn: error ${e}`); } diff --git a/src/vs/workbench/contrib/chat/browser/chatStatus.ts b/src/vs/workbench/contrib/chat/browser/chatStatus.ts index ced0ce0fd3ea6..f50bf3164f3bf 100644 --- a/src/vs/workbench/contrib/chat/browser/chatStatus.ts +++ b/src/vs/workbench/contrib/chat/browser/chatStatus.ts @@ -15,14 +15,14 @@ import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, ShowToolti import { ChatContextKeys } from '../common/chatContextKeys.js'; import { quotaToButtonMessage, OPEN_CHAT_QUOTA_EXCEEDED_DIALOG, CHAT_SETUP_ACTION_LABEL, TOGGLE_CHAT_ACTION_ID, CHAT_OPEN_ACTION_ID } from './actions/chatActions.js'; import { $, addDisposableListener, append, clearNode, EventHelper, EventLike, EventType } from '../../../../base/browser/dom.js'; -import { ChatEntitlement, IChatEntitlementService } from '../common/chatEntitlementService.js'; +import { ChatEntitlement, ChatEntitlementService, IChatEntitlementService } from '../common/chatEntitlementService.js'; import { CancellationToken } from '../../../../base/common/cancellation.js'; import { KeybindingLabel } from '../../../../base/browser/ui/keybindingLabel/keybindingLabel.js'; import { defaultCheckboxStyles, defaultKeybindingLabelStyles } from '../../../../platform/theme/browser/defaultStyles.js'; import { Checkbox } from '../../../../base/browser/ui/toggle/toggle.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { Command } from '../../../../editor/common/languages.js'; -import { ICommandService } from '../../../../platform/commands/common/commands.js'; +import { CommandsRegistry, ICommandService } from '../../../../platform/commands/common/commands.js'; import { Lazy } from '../../../../base/common/lazy.js'; import { contrastBorder, inputValidationErrorBorder, inputValidationInfoBorder, inputValidationWarningBorder, registerColor, transparent } from '../../../../platform/theme/common/colorRegistry.js'; import { IHoverService } from '../../../../platform/hover/browser/hover.js'; @@ -98,13 +98,15 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu private static readonly SETTING = 'chat.experimental.statusIndicator.enabled'; + private static readonly SIGN_IN_COMMAND_ID = 'workbench.action.chat.signIn'; + private entry: IStatusbarEntryAccessor | undefined = undefined; private dashboard = new Lazy(() => this.instantiationService.createInstance(ChatStatusDashboard)); constructor( @IStatusbarService private readonly statusbarService: IStatusbarService, - @IChatEntitlementService private readonly chatEntitlementService: IChatEntitlementService, + @IChatEntitlementService private readonly chatEntitlementService: ChatEntitlementService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @IConfigurationService private readonly configurationService: IConfigurationService, @IProductService private readonly productService: IProductService, @@ -114,6 +116,7 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu this.create(); this.registerListeners(); + this.registerCommands(); } private async create(): Promise { @@ -148,6 +151,12 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu this._register(this.chatEntitlementService.onDidChangeEntitlement(() => this.entry?.update(this.getEntryProps()))); } + private registerCommands(): void { + CommandsRegistry.registerCommand(ChatStatusBarEntry.SIGN_IN_COMMAND_ID, () => { + this.chatEntitlementService.requests?.value.signIn(); + }); + } + private getEntryProps(): IStatusbarEntry { let text = '$(copilot)'; let ariaLabel = localize('chatStatus', "Copilot Status"); @@ -185,10 +194,13 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu // Signed out else if (this.chatEntitlementService.entitlement === ChatEntitlement.Unknown) { - text = '$(copilot-not-connected)'; + text = '$(copilot-not-connected) Sign In to Use Copilot'; ariaLabel = localize('signInToUseCopilot', "Sign in to Use Copilot..."); - tooltip = localize('signInToUseCopilot', "Sign in to Use Copilot..."); - command = TOGGLE_CHAT_ACTION_ID; + tooltip = { + element: token => this.dashboard.value.show(token) + }; + command = ChatStatusBarEntry.SIGN_IN_COMMAND_ID; + kind = 'prominent'; } // Any other User diff --git a/src/vs/workbench/contrib/chat/common/chatEntitlementService.ts b/src/vs/workbench/contrib/chat/common/chatEntitlementService.ts index 2c9711944bbd1..cdfdedd106531 100644 --- a/src/vs/workbench/contrib/chat/common/chatEntitlementService.ts +++ b/src/vs/workbench/contrib/chat/common/chatEntitlementService.ts @@ -22,7 +22,7 @@ import { asText, IRequestService } from '../../../../platform/request/common/req import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; import { ITelemetryService, TelemetryLevel } from '../../../../platform/telemetry/common/telemetry.js'; import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; -import { AuthenticationSession, IAuthenticationService } from '../../../services/authentication/common/authentication.js'; +import { AuthenticationSession, IAuthenticationExtensionsService, IAuthenticationService } from '../../../services/authentication/common/authentication.js'; import { IWorkbenchExtensionEnablementService } from '../../../services/extensionManagement/common/extensionManagement.js'; import { IExtension, IExtensionsWorkbenchService } from '../../extensions/common/extensions.js'; import { ChatContextKeys } from './chatContextKeys.js'; @@ -81,6 +81,7 @@ export interface IChatEntitlementService { const defaultChat = { extensionId: product.defaultChatAgent?.extensionId ?? '', + chatExtensionId: product.defaultChatAgent?.chatExtensionId ?? '', upgradePlanUrl: product.defaultChatAgent?.upgradePlanUrl ?? '', providerId: product.defaultChatAgent?.providerId ?? '', enterpriseProviderId: product.defaultChatAgent?.enterpriseProviderId ?? '', @@ -325,7 +326,8 @@ export class ChatSetupRequests extends Disposable { @IRequestService private readonly requestService: IRequestService, @IDialogService private readonly dialogService: IDialogService, @IOpenerService private readonly openerService: IOpenerService, - @IConfigurationService private readonly configurationService: IConfigurationService + @IConfigurationService private readonly configurationService: IConfigurationService, + @IAuthenticationExtensionsService private readonly authenticationExtensionsService: IAuthenticationExtensionsService, ) { super(); @@ -667,6 +669,18 @@ export class ChatSetupRequests extends Disposable { }); } + async signIn() { + const providerId = ChatSetupRequests.providerId(this.configurationService); + const session = await this.authenticationService.createSession(providerId, defaultChat.providerScopes[0]); + + this.authenticationExtensionsService.updateAccountPreference(defaultChat.extensionId, providerId, session.account); + this.authenticationExtensionsService.updateAccountPreference(defaultChat.chatExtensionId, providerId, session.account); + + const entitlements = await this.forceResolveEntitlement(session); + + return { session, entitlements }; + } + override dispose(): void { this.pendingResolveCts.dispose(true);