Add sign in option for Apple (microsoft/vscode-internalbacklog#5578) (#255155)

This commit is contained in:
Benjamin Pasero 2025-07-10 23:43:10 +02:00 committed by GitHub
parent 141aa8582a
commit 2188c90df5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 95 additions and 114 deletions

View File

@ -571,14 +571,14 @@ export function getFlows(query: IFlowQuery) {
*/ */
export const enum GitHubSocialSignInProvider { export const enum GitHubSocialSignInProvider {
Google = 'google', Google = 'google',
// Apple = 'apple', Apple = 'apple',
} }
const GitHubSocialSignInProviderLabels = { const GitHubSocialSignInProviderLabels = {
[GitHubSocialSignInProvider.Google]: l10n.t('Google'), [GitHubSocialSignInProvider.Google]: l10n.t('Google'),
// [GitHubSocialSignInProvider.Apple]: l10n.t('Apple'), [GitHubSocialSignInProvider.Apple]: l10n.t('Apple'),
}; };
export function isSocialSignInProvider(provider: unknown): provider is GitHubSocialSignInProvider { export function isSocialSignInProvider(provider: unknown): provider is GitHubSocialSignInProvider {
return provider === GitHubSocialSignInProvider.Google; // || provider === GitHubSocialSignInProvider.Apple; return provider === GitHubSocialSignInProvider.Google || provider === GitHubSocialSignInProvider.Apple;
} }

View File

@ -1,7 +1,7 @@
{ {
"name": "code-oss-dev", "name": "code-oss-dev",
"version": "1.103.0", "version": "1.103.0",
"distro": "7fd50e9bdc1a124eb32a184ee4bc0d437cdae9f0", "distro": "e050762924418e1fb937b0aee594b586defeac82",
"author": { "author": {
"name": "Microsoft Corporation" "name": "Microsoft Corporation"
}, },

View File

@ -337,12 +337,13 @@ export interface IDefaultChatAgent {
readonly upgradePlanUrl: string; readonly upgradePlanUrl: string;
readonly signUpUrl: string; readonly signUpUrl: string;
readonly providerId: string; readonly provider: {
readonly providerName: string; default: { id: string; name: string };
readonly enterpriseProviderId: string; enterprise: { id: string; name: string };
readonly enterpriseProviderName: string; google: { id: string; name: string };
readonly alternativeProviderId: string; apple: { id: string; name: string };
readonly alternativeProviderName: string; };
readonly providerUriSetting: string; readonly providerUriSetting: string;
readonly providerScopes: string[][]; readonly providerScopes: string[][];

View File

@ -673,7 +673,7 @@ export function registerChatActions() {
} }
}); });
const nonEnterpriseCopilotUsers = ContextKeyExpr.and(ChatContextKeys.enabled, ContextKeyExpr.notEquals(`config.${defaultChat.completionsAdvancedSetting}.authProvider`, defaultChat.enterpriseProviderId)); const nonEnterpriseCopilotUsers = ContextKeyExpr.and(ChatContextKeys.enabled, ContextKeyExpr.notEquals(`config.${defaultChat.completionsAdvancedSetting}.authProvider`, defaultChat.provider?.enterprise.id));
registerAction2(class extends Action2 { registerAction2(class extends Action2 {
constructor() { constructor() {
super({ super({
@ -901,7 +901,7 @@ const defaultChat = {
documentationUrl: product.defaultChatAgent?.documentationUrl ?? '', documentationUrl: product.defaultChatAgent?.documentationUrl ?? '',
manageSettingsUrl: product.defaultChatAgent?.manageSettingsUrl ?? '', manageSettingsUrl: product.defaultChatAgent?.manageSettingsUrl ?? '',
managePlanUrl: product.defaultChatAgent?.managePlanUrl ?? '', managePlanUrl: product.defaultChatAgent?.managePlanUrl ?? '',
enterpriseProviderId: product.defaultChatAgent?.enterpriseProviderId ?? '', provider: product.defaultChatAgent?.provider ?? { enterprise: { id: '' } },
completionsAdvancedSetting: product.defaultChatAgent?.completionsAdvancedSetting ?? '', completionsAdvancedSetting: product.defaultChatAgent?.completionsAdvancedSetting ?? '',
completionsMenuCommand: product.defaultChatAgent?.completionsMenuCommand ?? '', completionsMenuCommand: product.defaultChatAgent?.completionsMenuCommand ?? '',
}; };

View File

@ -478,7 +478,7 @@ configurationRegistry.registerConfiguration({
}, },
'chat.setup.signInDialogVariant': { // TODO@bpasero remove me eventually 'chat.setup.signInDialogVariant': { // TODO@bpasero remove me eventually
type: 'string', type: 'string',
enum: ['default', 'alternate-first', 'alternate-color', 'alternate-monochrome'], enum: ['default', 'apple'],
description: nls.localize('chat.signInDialogVariant', "Control variations of the sign-in dialog."), description: nls.localize('chat.signInDialogVariant', "Control variations of the sign-in dialog."),
default: 'default', default: 'default',
tags: ['onExp', 'experimental'] tags: ['onExp', 'experimental']

View File

@ -80,13 +80,7 @@ const defaultChat = {
publicCodeMatchesUrl: product.defaultChatAgent?.publicCodeMatchesUrl ?? '', publicCodeMatchesUrl: product.defaultChatAgent?.publicCodeMatchesUrl ?? '',
manageOveragesUrl: product.defaultChatAgent?.manageOverageUrl ?? '', manageOveragesUrl: product.defaultChatAgent?.manageOverageUrl ?? '',
upgradePlanUrl: product.defaultChatAgent?.upgradePlanUrl ?? '', upgradePlanUrl: product.defaultChatAgent?.upgradePlanUrl ?? '',
signUpUrl: product.defaultChatAgent?.signUpUrl ?? '', provider: product.defaultChatAgent?.provider ?? { default: { id: '', name: '' }, enterprise: { id: '', name: '' }, apple: { id: '', name: '' }, google: { id: '', name: '' } },
providerId: product.defaultChatAgent?.providerId ?? '',
providerName: product.defaultChatAgent?.providerName ?? '',
enterpriseProviderId: product.defaultChatAgent?.enterpriseProviderId ?? '',
enterpriseProviderName: product.defaultChatAgent?.enterpriseProviderName ?? '',
alternativeProviderId: product.defaultChatAgent?.alternativeProviderId ?? '',
alternativeProviderName: product.defaultChatAgent?.alternativeProviderName ?? '',
providerUriSetting: product.defaultChatAgent?.providerUriSetting ?? '', providerUriSetting: product.defaultChatAgent?.providerUriSetting ?? '',
providerScopes: product.defaultChatAgent?.providerScopes ?? [[]], providerScopes: product.defaultChatAgent?.providerScopes ?? [[]],
manageSettingsUrl: product.defaultChatAgent?.manageSettingsUrl ?? '', manageSettingsUrl: product.defaultChatAgent?.manageSettingsUrl ?? '',
@ -134,7 +128,7 @@ class SetupAgent extends Disposable implements IChatAgentImplementation {
break; break;
} }
return SetupAgent.doRegisterAgent(instantiationService, chatAgentService, id, `${defaultChat.providerName} Copilot`, true, description, location, mode, context, controller); return SetupAgent.doRegisterAgent(instantiationService, chatAgentService, id, `${defaultChat.provider?.default.name} Copilot`, true, description, location, mode, context, controller);
}); });
} }
@ -307,9 +301,9 @@ class SetupAgent extends Disposable implements IChatAgentImplementation {
if (ready === 'error' || ready === 'timedout') { if (ready === 'error' || ready === 'timedout') {
let warningMessage: string; let warningMessage: string;
if (ready === 'timedout') { if (ready === 'timedout') {
warningMessage = localize('copilotTookLongWarning', "Copilot took too long to get ready. Please ensure you are signed in to {0} and that the extension `{1}` is installed and enabled.", defaultChat.providerName, defaultChat.chatExtensionId); warningMessage = localize('copilotTookLongWarning', "Copilot took too long to get ready. Please ensure you are signed in to {0} and that the extension `{1}` is installed and enabled.", defaultChat.provider?.default.name, defaultChat.chatExtensionId);
} else { } else {
warningMessage = localize('copilotFailedWarning', "Copilot failed to get ready. Please ensure you are signed in to {0} and that the extension `{1}` is installed and enabled.", defaultChat.providerName, defaultChat.chatExtensionId); warningMessage = localize('copilotFailedWarning', "Copilot failed to get ready. Please ensure you are signed in to {0} and that the extension `{1}` is installed and enabled.", defaultChat.provider?.default.name, defaultChat.chatExtensionId);
} }
progress({ progress({
@ -398,7 +392,7 @@ class SetupAgent extends Disposable implements IChatAgentImplementation {
case ChatSetupStep.SigningIn: case ChatSetupStep.SigningIn:
progress({ progress({
kind: 'progressMessage', kind: 'progressMessage',
content: new MarkdownString(localize('setupChatSignIn2', "Signing in to {0}.", ChatEntitlementRequests.providerId(this.configurationService) === defaultChat.enterpriseProviderId ? defaultChat.enterpriseProviderName : defaultChat.providerName)), content: new MarkdownString(localize('setupChatSignIn2', "Signing in to {0}.", ChatEntitlementRequests.providerId(this.configurationService) === defaultChat.provider?.enterprise.id ? defaultChat.provider?.enterprise.name : defaultChat.provider?.default.name)),
}); });
break; break;
case ChatSetupStep.Installing: case ChatSetupStep.Installing:
@ -575,8 +569,8 @@ enum ChatSetupStrategy {
DefaultSetup = 1, DefaultSetup = 1,
SetupWithoutEnterpriseProvider = 2, SetupWithoutEnterpriseProvider = 2,
SetupWithEnterpriseProvider = 3, SetupWithEnterpriseProvider = 3,
SetupWithAccountCreate = 4, SetupWithGoogleProvider = 4,
SetupWithAlternateProvider = 5 SetupWithAppleProvider = 5
} }
type ChatSetupResultValue = boolean /* success */ | undefined /* canceled */; type ChatSetupResultValue = boolean /* success */ | undefined /* canceled */;
@ -593,7 +587,7 @@ class ChatSetup {
let instance = ChatSetup.instance; let instance = ChatSetup.instance;
if (!instance) { if (!instance) {
instance = ChatSetup.instance = instantiationService.invokeFunction(accessor => { instance = ChatSetup.instance = instantiationService.invokeFunction(accessor => {
return new ChatSetup(context, controller, instantiationService, accessor.get(ITelemetryService), accessor.get(IWorkbenchLayoutService), accessor.get(IKeybindingService), accessor.get(IChatEntitlementService) as ChatEntitlementService, accessor.get(ILogService), accessor.get(IConfigurationService), accessor.get(IViewsService), accessor.get(IOpenerService), accessor.get(IWorkspaceTrustRequestService)); return new ChatSetup(context, controller, instantiationService, accessor.get(ITelemetryService), accessor.get(IWorkbenchLayoutService), accessor.get(IKeybindingService), accessor.get(IChatEntitlementService) as ChatEntitlementService, accessor.get(ILogService), accessor.get(IConfigurationService), accessor.get(IViewsService), accessor.get(IWorkspaceTrustRequestService));
}); });
} }
@ -615,7 +609,6 @@ class ChatSetup {
@ILogService private readonly logService: ILogService, @ILogService private readonly logService: ILogService,
@IConfigurationService private readonly configurationService: IConfigurationService, @IConfigurationService private readonly configurationService: IConfigurationService,
@IViewsService private readonly viewsService: IViewsService, @IViewsService private readonly viewsService: IViewsService,
@IOpenerService private readonly openerService: IOpenerService,
@IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService
) { } ) { }
@ -660,7 +653,7 @@ class ChatSetup {
setupStrategy = await this.showDialog(); setupStrategy = await this.showDialog();
} }
if (setupStrategy === ChatSetupStrategy.DefaultSetup && ChatEntitlementRequests.providerId(this.configurationService) === defaultChat.enterpriseProviderId) { if (setupStrategy === ChatSetupStrategy.DefaultSetup && ChatEntitlementRequests.providerId(this.configurationService) === defaultChat.provider?.enterprise.id) {
setupStrategy = ChatSetupStrategy.SetupWithEnterpriseProvider; // users with a configured provider go through provider setup setupStrategy = ChatSetupStrategy.SetupWithEnterpriseProvider; // users with a configured provider go through provider setup
} }
@ -674,20 +667,20 @@ class ChatSetup {
try { try {
switch (setupStrategy) { switch (setupStrategy) {
case ChatSetupStrategy.SetupWithEnterpriseProvider: case ChatSetupStrategy.SetupWithEnterpriseProvider:
success = await this.controller.value.setupWithProvider({ useEnterpriseProvider: true, useAlternateProvider: false }); success = await this.controller.value.setupWithProvider({ useEnterpriseProvider: true, useSocialProvider: undefined });
break; break;
case ChatSetupStrategy.SetupWithoutEnterpriseProvider: case ChatSetupStrategy.SetupWithoutEnterpriseProvider:
success = await this.controller.value.setupWithProvider({ useEnterpriseProvider: false, useAlternateProvider: false }); success = await this.controller.value.setupWithProvider({ useEnterpriseProvider: false, useSocialProvider: undefined });
break; break;
case ChatSetupStrategy.SetupWithAlternateProvider: case ChatSetupStrategy.SetupWithAppleProvider:
success = await this.controller.value.setupWithProvider({ useEnterpriseProvider: false, useAlternateProvider: true }); success = await this.controller.value.setupWithProvider({ useEnterpriseProvider: false, useSocialProvider: 'apple' });
break;
case ChatSetupStrategy.SetupWithGoogleProvider:
success = await this.controller.value.setupWithProvider({ useEnterpriseProvider: false, useSocialProvider: 'google' });
break; break;
case ChatSetupStrategy.DefaultSetup: case ChatSetupStrategy.DefaultSetup:
success = await this.controller.value.setup(); success = await this.controller.value.setup();
break; break;
case ChatSetupStrategy.SetupWithAccountCreate:
this.openerService.open(URI.parse(defaultChat.signUpUrl));
return this.doRun(options); // open dialog again
case ChatSetupStrategy.Canceled: case ChatSetupStrategy.Canceled:
this.context.update({ later: true }); this.context.update({ later: true });
this.telemetryService.publicLog2<InstallChatEvent, InstallChatClassification>('commandCenter.chatInstall', { installResult: 'failedMaybeLater', installDuration: 0, signUpErrorCode: undefined, provider: undefined }); this.telemetryService.publicLog2<InstallChatEvent, InstallChatClassification>('commandCenter.chatInstall', { installResult: 'failedMaybeLater', installDuration: 0, signUpErrorCode: undefined, provider: undefined });
@ -704,7 +697,7 @@ class ChatSetup {
private async showDialog(): Promise<ChatSetupStrategy> { private async showDialog(): Promise<ChatSetupStrategy> {
const disposables = new DisposableStore(); const disposables = new DisposableStore();
const dialogVariant = this.configurationService.getValue<'default' | 'alternate-first' | 'alternate-color' | 'alternate-monochrome' | unknown>('chat.setup.signInDialogVariant'); const dialogVariant = this.configurationService.getValue<'default' | 'apple' | unknown>('chat.setup.signInDialogVariant');
const buttons = this.getButtons(dialogVariant); const buttons = this.getButtons(dialogVariant);
const dialog = disposables.add(new Dialog( const dialog = disposables.add(new Dialog(
@ -730,59 +723,41 @@ class ChatSetup {
return buttons[button]?.[1] ?? ChatSetupStrategy.Canceled; return buttons[button]?.[1] ?? ChatSetupStrategy.Canceled;
} }
private getButtons(variant: 'default' | 'alternate-first' | 'alternate-color' | 'alternate-monochrome' | unknown): Array<[string, ChatSetupStrategy, { styleButton?: (button: IButton) => void } | undefined]> { private getButtons(variant: 'default' | 'apple' | unknown): Array<[string, ChatSetupStrategy, { styleButton?: (button: IButton) => void } | undefined]> {
let buttons: Array<[string, ChatSetupStrategy, { styleButton?: (button: IButton) => void } | undefined]>; type ContinueWithButton = [string, ChatSetupStrategy, { styleButton?: (button: IButton) => void } | undefined];
const styleButton = (...classes: string[]) => ({ styleButton: (button: IButton) => button.element.classList.add(...classes) });
let buttons: Array<ContinueWithButton>;
if (this.context.state.entitlement === ChatEntitlement.Unknown) { if (this.context.state.entitlement === ChatEntitlement.Unknown) {
let alternateProvider: 'off' | 'monochrome' | 'colorful' | 'first' = 'off'; const defaultProviderButton: ContinueWithButton = [localize('continueWith', "Continue with {0}", defaultChat.provider?.default.name), ChatSetupStrategy.SetupWithoutEnterpriseProvider, styleButton('continue-button', 'default')];
if (defaultChat.alternativeProviderId) { const defaultProviderLink: ContinueWithButton = [defaultProviderButton[0], defaultProviderButton[1], styleButton('link-button')];
switch (variant) {
case 'alternate-first':
alternateProvider = 'first';
break;
case 'alternate-color':
alternateProvider = 'colorful';
break;
case 'alternate-monochrome':
alternateProvider = 'monochrome';
break;
}
}
if (ChatEntitlementRequests.providerId(this.configurationService) === defaultChat.enterpriseProviderId) { const enterpriseProviderButton: ContinueWithButton = [localize('continueWith', "Continue with {0}", defaultChat.provider?.enterprise.name), ChatSetupStrategy.SetupWithEnterpriseProvider, styleButton('continue-button', 'default')];
const enterpriseProviderLink: ContinueWithButton = [enterpriseProviderButton[0], enterpriseProviderButton[1], styleButton('link-button')];
const googleProviderButton: ContinueWithButton = [localize('continueWith', "Continue with {0}", defaultChat.provider?.google.name), ChatSetupStrategy.SetupWithGoogleProvider, styleButton('continue-button', 'google')];
const appleProviderButton: ContinueWithButton = [localize('continueWith', "Continue with {0}", defaultChat.provider?.apple.name), ChatSetupStrategy.SetupWithAppleProvider, styleButton('continue-button', 'apple')];
if (ChatEntitlementRequests.providerId(this.configurationService) !== defaultChat.provider?.enterprise.id) {
buttons = coalesce([ buttons = coalesce([
[localize('continueWith', "Continue with {0}", defaultChat.enterpriseProviderName), ChatSetupStrategy.SetupWithEnterpriseProvider, { defaultProviderButton,
styleButton: button => button.element.classList.add('continue-button', 'default') googleProviderButton,
}], variant === 'apple' ? appleProviderButton : undefined,
alternateProvider !== 'off' ? [localize('continueWith', "Continue with {0}", defaultChat.alternativeProviderName), ChatSetupStrategy.SetupWithAlternateProvider, { enterpriseProviderLink
styleButton: button => button.element.classList.add('continue-button', 'alternate', alternateProvider)
}] : undefined,
[localize('signInWithProvider', "Sign in with a {0} account", defaultChat.providerName), ChatSetupStrategy.SetupWithoutEnterpriseProvider, {
styleButton: button => button.element.classList.add('link-button')
}]
]); ]);
} else { } else {
buttons = coalesce([ buttons = coalesce([
[localize('continueWith', "Continue with {0}", defaultChat.providerName), ChatSetupStrategy.SetupWithoutEnterpriseProvider, { enterpriseProviderButton,
styleButton: button => button.element.classList.add('continue-button', 'default') googleProviderButton,
}], variant === 'apple' ? appleProviderButton : undefined,
alternateProvider !== 'off' ? [localize('continueWith', "Continue with {0}", defaultChat.alternativeProviderName), ChatSetupStrategy.SetupWithAlternateProvider, { defaultProviderLink
styleButton: button => button.element.classList.add('continue-button', 'alternate', alternateProvider)
}] : undefined,
[localize('signInWithProvider', "Sign in with a {0} account", defaultChat.enterpriseProviderName), ChatSetupStrategy.SetupWithEnterpriseProvider, {
styleButton: button => button.element.classList.add('link-button')
}]
]); ]);
} }
if (alternateProvider === 'first') {
[buttons[0], buttons[1]] = [buttons[1], buttons[0]];
}
} else { } else {
buttons = [[localize('setupCopilotButton', "Set up Copilot"), ChatSetupStrategy.DefaultSetup, undefined]]; buttons = [[localize('setupCopilotButton', "Set up Copilot"), ChatSetupStrategy.DefaultSetup, undefined]];
} }
buttons.push([localize('skipForNow', "Skip for now"), ChatSetupStrategy.Canceled, { styleButton: button => button.element.classList.add('link-button', 'skip-button') }]); buttons.push([localize('skipForNow', "Skip for now"), ChatSetupStrategy.Canceled, styleButton('link-button', 'skip-button')]);
return buttons; return buttons;
} }
@ -801,7 +776,7 @@ class ChatSetup {
const markdown = this.instantiationService.createInstance(MarkdownRenderer, {}); const markdown = this.instantiationService.createInstance(MarkdownRenderer, {});
// SKU Settings // SKU Settings
const settings = localize({ key: 'settings', comment: ['{Locked="["}', '{Locked="]({0})"}', '{Locked="]({1})"}'] }, "{0} Copilot Free, Pro and Pro+ may show [public code]({1}) suggestions and we may use your data for product improvement. You can change these [settings]({2}) at any time.", defaultChat.providerName, defaultChat.publicCodeMatchesUrl, defaultChat.manageSettingsUrl); const settings = localize({ key: 'settings', comment: ['{Locked="["}', '{Locked="]({0})"}', '{Locked="]({1})"}'] }, "{0} Copilot Free, Pro and Pro+ may show [public code]({1}) suggestions and we may use your data for product improvement. You can change these [settings]({2}) at any time.", defaultChat.provider?.default.name, defaultChat.publicCodeMatchesUrl, defaultChat.manageSettingsUrl);
element.appendChild($('p', undefined, disposables.add(markdown.render(new MarkdownString(settings, { isTrusted: true }))).element)); element.appendChild($('p', undefined, disposables.add(markdown.render(new MarkdownString(settings, { isTrusted: true }))).element));
return element; return element;
@ -1221,7 +1196,7 @@ class ChatSetupController extends Disposable {
this._onDidChange.fire(); this._onDidChange.fire();
} }
async setup(options?: { forceSignIn?: boolean; useAlternateProvider?: boolean; useEnterpriseProvider?: boolean }): Promise<ChatSetupResultValue> { async setup(options?: { forceSignIn?: boolean; useSocialProvider?: string; useEnterpriseProvider?: boolean }): Promise<ChatSetupResultValue> {
const watch = new StopWatch(false); const watch = new StopWatch(false);
const title = localize('setupChatProgress', "Getting Copilot ready..."); const title = localize('setupChatProgress', "Getting Copilot ready...");
const badge = this.activityService.showViewContainerActivity(CHAT_SIDEBAR_PANEL_ID, { const badge = this.activityService.showViewContainerActivity(CHAT_SIDEBAR_PANEL_ID, {
@ -1239,7 +1214,7 @@ class ChatSetupController extends Disposable {
} }
} }
private async doSetup(options: { forceSignIn?: boolean; useAlternateProvider?: boolean; useEnterpriseProvider?: boolean }, watch: StopWatch): Promise<ChatSetupResultValue> { private async doSetup(options: { forceSignIn?: boolean; useSocialProvider?: string; useEnterpriseProvider?: boolean }, watch: StopWatch): Promise<ChatSetupResultValue> {
this.context.suspend(); // reduces flicker this.context.suspend(); // reduces flicker
let success: ChatSetupResultValue = false; let success: ChatSetupResultValue = false;
@ -1251,11 +1226,11 @@ class ChatSetupController extends Disposable {
// Entitlement Unknown or `forceSignIn`: we need to sign-in user // Entitlement Unknown or `forceSignIn`: we need to sign-in user
if (this.context.state.entitlement === ChatEntitlement.Unknown || options.forceSignIn) { if (this.context.state.entitlement === ChatEntitlement.Unknown || options.forceSignIn) {
this.setStep(ChatSetupStep.SigningIn); this.setStep(ChatSetupStep.SigningIn);
const result = await this.signIn({ useAlternateProvider: options.useAlternateProvider }); const result = await this.signIn(options);
if (!result.session) { if (!result.session) {
this.doInstall(); // still install the extension in the background to remind the user to sign-in eventually this.doInstall(); // still install the extension in the background to remind the user to sign-in eventually
const provider = options.useAlternateProvider ? defaultChat.alternativeProviderId : options.useEnterpriseProvider ? defaultChat.enterpriseProviderId : defaultChat.providerId; const provider = options.useSocialProvider ?? options.useEnterpriseProvider ? defaultChat.provider?.enterprise.id : defaultChat.provider?.default.id;
this.telemetryService.publicLog2<InstallChatEvent, InstallChatClassification>('commandCenter.chatInstall', { installResult: 'failedNotSignedIn', installDuration: watch.elapsed(), signUpErrorCode: undefined, provider }); this.telemetryService.publicLog2<InstallChatEvent, InstallChatClassification>('commandCenter.chatInstall', { installResult: 'failedNotSignedIn', installDuration: watch.elapsed(), signUpErrorCode: undefined, provider });
return undefined; // treat as cancelled because signing in already triggers an error dialog return undefined; // treat as cancelled because signing in already triggers an error dialog
} }
@ -1275,7 +1250,7 @@ class ChatSetupController extends Disposable {
return success; return success;
} }
private async signIn(options: { useAlternateProvider?: boolean }): Promise<{ session: AuthenticationSession | undefined; entitlement: ChatEntitlement | undefined }> { private async signIn(options: { useSocialProvider?: string }): Promise<{ session: AuthenticationSession | undefined; entitlement: ChatEntitlement | undefined }> {
let session: AuthenticationSession | undefined; let session: AuthenticationSession | undefined;
let entitlements; let entitlements;
try { try {
@ -1287,7 +1262,7 @@ class ChatSetupController extends Disposable {
if (!session && !this.lifecycleService.willShutdown) { if (!session && !this.lifecycleService.willShutdown) {
const { confirmed } = await this.dialogService.confirm({ const { confirmed } = await this.dialogService.confirm({
type: Severity.Error, type: Severity.Error,
message: localize('unknownSignInError', "Failed to sign in to {0}. Would you like to try again?", options?.useAlternateProvider ? defaultChat.alternativeProviderName : ChatEntitlementRequests.providerId(this.configurationService) === defaultChat.enterpriseProviderId ? defaultChat.enterpriseProviderName : defaultChat.providerName), message: localize('unknownSignInError', "Failed to sign in to {0}. Would you like to try again?", ChatEntitlementRequests.providerId(this.configurationService) === defaultChat.provider?.enterprise.id ? defaultChat.provider?.enterprise.name : defaultChat.provider?.default.name),
detail: localize('unknownSignInErrorDetail', "You must be signed in to use Copilot."), detail: localize('unknownSignInErrorDetail', "You must be signed in to use Copilot."),
primaryButton: localize('retry', "Retry") primaryButton: localize('retry', "Retry")
}); });
@ -1300,11 +1275,11 @@ class ChatSetupController extends Disposable {
return { session, entitlement: entitlements?.entitlement }; return { session, entitlement: entitlements?.entitlement };
} }
private async install(session: AuthenticationSession | undefined, entitlement: ChatEntitlement, providerId: string, watch: StopWatch, options: { useAlternateProvider?: boolean; useEnterpriseProvider?: boolean }): Promise<ChatSetupResultValue> { private async install(session: AuthenticationSession | undefined, entitlement: ChatEntitlement, providerId: string, watch: StopWatch, options: { useSocialProvider?: string; useEnterpriseProvider?: boolean }): Promise<ChatSetupResultValue> {
const wasRunning = this.context.state.installed && !this.context.state.disabled; const wasRunning = this.context.state.installed && !this.context.state.disabled;
let signUpResult: boolean | { errorCode: number } | undefined = undefined; let signUpResult: boolean | { errorCode: number } | undefined = undefined;
const provider = options.useAlternateProvider ? defaultChat.alternativeProviderId : options.useEnterpriseProvider ? defaultChat.enterpriseProviderId : defaultChat.providerId; const provider = options.useSocialProvider ?? options.useEnterpriseProvider ? defaultChat.provider?.enterprise.id : defaultChat.provider?.default.id;
try { try {
@ -1392,7 +1367,7 @@ class ChatSetupController extends Disposable {
}, ChatViewId); }, ChatViewId);
} }
async setupWithProvider(options: { useEnterpriseProvider: boolean; useAlternateProvider: boolean }): Promise<ChatSetupResultValue> { async setupWithProvider(options: { useEnterpriseProvider: boolean; useSocialProvider: string | undefined }): Promise<ChatSetupResultValue> {
const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration); const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
registry.registerConfiguration({ registry.registerConfiguration({
'id': 'copilot.setup', 'id': 'copilot.setup',
@ -1427,7 +1402,7 @@ class ChatSetupController extends Disposable {
if (options.useEnterpriseProvider) { if (options.useEnterpriseProvider) {
await this.configurationService.updateValue(`${defaultChat.completionsAdvancedSetting}`, { await this.configurationService.updateValue(`${defaultChat.completionsAdvancedSetting}`, {
...existingAdvancedSetting, ...existingAdvancedSetting,
'authProvider': defaultChat.enterpriseProviderId 'authProvider': defaultChat.provider?.enterprise.id
}, ConfigurationTarget.USER); }, ConfigurationTarget.USER);
} else { } else {
await this.configurationService.updateValue(`${defaultChat.completionsAdvancedSetting}`, Object.keys(existingAdvancedSetting).length > 0 ? { await this.configurationService.updateValue(`${defaultChat.completionsAdvancedSetting}`, Object.keys(existingAdvancedSetting).length > 0 ? {
@ -1450,7 +1425,7 @@ class ChatSetupController extends Disposable {
let isSingleWord = false; let isSingleWord = false;
const result = await this.quickInputService.input({ const result = await this.quickInputService.input({
prompt: localize('enterpriseInstance', "What is your {0} instance?", defaultChat.enterpriseProviderName), prompt: localize('enterpriseInstance', "What is your {0} instance?", defaultChat.provider?.enterprise.name),
placeHolder: localize('enterpriseInstancePlaceholder', 'i.e. "octocat" or "https://octocat.ghe.com"...'), placeHolder: localize('enterpriseInstancePlaceholder', 'i.e. "octocat" or "https://octocat.ghe.com"...'),
ignoreFocusLost: true, ignoreFocusLost: true,
value: uri, value: uri,
@ -1468,7 +1443,7 @@ class ChatSetupController extends Disposable {
}; };
} if (!fullUriRegEx.test(value)) { } if (!fullUriRegEx.test(value)) {
return { return {
content: localize('invalidEnterpriseInstance', 'You must enter a valid {0} instance (i.e. "octocat" or "https://octocat.ghe.com")', defaultChat.enterpriseProviderName), content: localize('invalidEnterpriseInstance', 'You must enter a valid {0} instance (i.e. "octocat" or "https://octocat.ghe.com")', defaultChat.provider?.enterprise.name),
severity: Severity.Error severity: Severity.Error
}; };
} }

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.15673 3C8.7435 3 9.47904 2.60331 9.91706 2.07438C10.3137 1.59504 10.603 0.92562 10.603 0.256199C10.603 0.165289 10.5947 0.0743802 10.5782 0C9.92532 0.0247934 9.1402 0.438017 8.66912 0.991736C8.29722 1.41322 7.95838 2.07438 7.95838 2.75207C7.95838 2.85124 7.97491 2.95041 7.98317 2.98347C8.0245 2.99174 8.09061 3 8.15673 3ZM6.09061 13C6.89226 13 7.24764 12.4628 8.24764 12.4628C9.26417 12.4628 9.48731 12.9835 10.3798 12.9835C11.2559 12.9835 11.8427 12.1736 12.3964 11.3802C13.0162 10.4711 13.2724 9.57851 13.2889 9.53719C13.2311 9.52066 11.5534 8.83471 11.5534 6.90909C11.5534 5.23967 12.8757 4.4876 12.9501 4.42975C12.0741 3.17355 10.7435 3.1405 10.3798 3.1405C9.3964 3.1405 8.59474 3.73554 8.09061 3.73554C7.54516 3.73554 6.82615 3.17355 5.97491 3.17355C4.35507 3.17355 2.71045 4.5124 2.71045 7.04132C2.71045 8.61157 3.32202 10.2727 4.07408 11.3471C4.71871 12.2562 5.28069 13 6.09061 13Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1021 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.15661 3C8.74338 3 9.47892 2.60331 9.91694 2.07438C10.3136 1.59504 10.6029 0.92562 10.6029 0.256199C10.6029 0.165289 10.5946 0.0743802 10.5781 0C9.9252 0.0247934 9.14008 0.438017 8.669 0.991736C8.2971 1.41322 7.95826 2.07438 7.95826 2.75207C7.95826 2.85124 7.97479 2.95041 7.98305 2.98347C8.02438 2.99174 8.09049 3 8.15661 3ZM6.09049 13C6.89214 13 7.24752 12.4628 8.24752 12.4628C9.26405 12.4628 9.48719 12.9835 10.3797 12.9835C11.2558 12.9835 11.8426 12.1736 12.3963 11.3802C13.0161 10.4711 13.2723 9.57851 13.2888 9.53719C13.231 9.52066 11.5533 8.83471 11.5533 6.90909C11.5533 5.23967 12.8756 4.4876 12.95 4.42975C12.074 3.17355 10.7434 3.1405 10.3797 3.1405C9.39628 3.1405 8.59462 3.73554 8.09049 3.73554C7.54504 3.73554 6.82603 3.17355 5.97479 3.17355C4.35495 3.17355 2.71033 4.5124 2.71033 7.04132C2.71033 8.61157 3.3219 10.2727 4.07396 11.3471C4.71859 12.2562 5.28057 13 6.09049 13Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1019 B

View File

@ -23,7 +23,7 @@
background-image: url('./github.svg'); background-image: url('./github.svg');
} }
.dialog-buttons-row > .dialog-buttons > .monaco-button.continue-button.alternate::before { .dialog-buttons-row > .dialog-buttons > .monaco-button.continue-button.google::before {
background-image: url('./google.svg'); background-image: url('./google.svg');
} }
@ -51,12 +51,12 @@
} }
} }
.monaco-workbench.hc-black .chat-setup-dialog .dialog-buttons-row > .dialog-buttons > .monaco-button.continue-button.alternate.monochrome::before, .monaco-workbench.hc-black .chat-setup-dialog .dialog-buttons-row > .dialog-buttons > .monaco-button.continue-button.apple::before,
.monaco-workbench.vs-dark .chat-setup-dialog .dialog-buttons-row > .dialog-buttons > .monaco-button.continue-button.alternate.monochrome::before { .monaco-workbench.vs-dark .chat-setup-dialog .dialog-buttons-row > .dialog-buttons > .monaco-button.continue-button.apple::before {
background-image: url('./google-mono-dark.svg'); background-image: url('./apple-dark.svg');
} }
.monaco-workbench.hc-light .chat-setup-dialog .dialog-buttons-row > .dialog-buttons > .monaco-button.continue-button.alternate.monochrome::before, .monaco-workbench.hc-light .chat-setup-dialog .dialog-buttons-row > .dialog-buttons > .monaco-button.continue-button.apple::before,
.monaco-workbench.vs .chat-setup-dialog .dialog-buttons-row > .dialog-buttons > .monaco-button.continue-button.alternate.monochrome::before { .monaco-workbench.vs .chat-setup-dialog .dialog-buttons-row > .dialog-buttons > .monaco-button.continue-button.apple::before {
background-image: url('./google-mono-light.svg'); background-image: url('./apple-light.svg');
} }

View File

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 0C10.1563 1.22707e-05 11.967 0.793114 13.3525 2.08398L11.0576 4.37793C10.2286 3.58545 9.17429 3.18165 8 3.18164C5.91632 3.18164 4.15256 4.58959 3.52344 6.48047L3.41699 6.8457C3.32391 7.21717 3.27246 7.60448 3.27246 8C3.27246 8.52711 3.36354 9.03967 3.52344 9.51953C4.15267 11.4102 5.91647 12.8184 8 12.8184C9.07626 12.8184 9.99268 12.5346 10.709 12.0547L10.8643 11.9453C11.6252 11.3811 12.1318 10.5773 12.3057 9.63965H8V6.5459H15.5342C15.6286 7.0694 15.6797 7.61457 15.6797 8.18164C15.6797 10.6178 14.8074 12.6688 13.2949 14.0615H13.2939C11.9704 15.2833 10.16 16 8 16C4.97035 16 2.33693 14.3173 0.978516 11.835L0.850586 11.5928L0.65918 11.1816C0.236933 10.2065 0 9.12972 0 8C1.14184e-06 6.70915 0.308848 5.48721 0.850586 4.40723C2.16699 1.79267 4.87272 0 8 0Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 891 B

View File

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 0C10.1563 1.22707e-05 11.967 0.793114 13.3525 2.08398L11.0576 4.37793C10.2286 3.58545 9.17429 3.18165 8 3.18164C5.91632 3.18164 4.15256 4.58959 3.52344 6.48047L3.41699 6.8457C3.32391 7.21717 3.27246 7.60448 3.27246 8C3.27246 8.52711 3.36354 9.03967 3.52344 9.51953V9.52051C4.15267 11.4112 5.91647 12.8184 8 12.8184C9.07626 12.8184 9.99268 12.5346 10.709 12.0547L10.8643 11.9453C11.6252 11.3811 12.1318 10.5773 12.3057 9.63965H8V6.5459H15.5342C15.6286 7.0694 15.6797 7.61457 15.6797 8.18164C15.6797 10.6178 14.8074 12.6688 13.2949 14.0615H13.2939C11.9704 15.2833 10.16 16 8 16C4.97035 16 2.33693 14.3173 0.978516 11.835L0.850586 11.5928L0.65918 11.1816C0.236933 10.2065 0 9.12972 0 8C1.14184e-06 6.70915 0.308848 5.48721 0.850586 4.40723C2.16699 1.79267 4.87272 0 8 0Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 899 B

View File

@ -134,9 +134,7 @@ const defaultChat = {
extensionId: product.defaultChatAgent?.extensionId ?? '', extensionId: product.defaultChatAgent?.extensionId ?? '',
chatExtensionId: product.defaultChatAgent?.chatExtensionId ?? '', chatExtensionId: product.defaultChatAgent?.chatExtensionId ?? '',
upgradePlanUrl: product.defaultChatAgent?.upgradePlanUrl ?? '', upgradePlanUrl: product.defaultChatAgent?.upgradePlanUrl ?? '',
providerId: product.defaultChatAgent?.providerId ?? '', provider: product.defaultChatAgent?.provider ?? { default: { id: '' }, enterprise: { id: '' } },
enterpriseProviderId: product.defaultChatAgent?.enterpriseProviderId ?? '',
alternativeProviderId: product.defaultChatAgent?.alternativeProviderId ?? '',
providerScopes: product.defaultChatAgent?.providerScopes ?? [[]], providerScopes: product.defaultChatAgent?.providerScopes ?? [[]],
entitlementUrl: product.defaultChatAgent?.entitlementUrl ?? '', entitlementUrl: product.defaultChatAgent?.entitlementUrl ?? '',
entitlementSignupLimitedUrl: product.defaultChatAgent?.entitlementSignupLimitedUrl ?? '', entitlementSignupLimitedUrl: product.defaultChatAgent?.entitlementSignupLimitedUrl ?? '',
@ -421,11 +419,11 @@ interface IQuotas {
export class ChatEntitlementRequests extends Disposable { export class ChatEntitlementRequests extends Disposable {
static providerId(configurationService: IConfigurationService): string { static providerId(configurationService: IConfigurationService): string {
if (configurationService.getValue<string | undefined>(`${defaultChat.completionsAdvancedSetting}.authProvider`) === defaultChat.enterpriseProviderId) { if (configurationService.getValue<string | undefined>(`${defaultChat.completionsAdvancedSetting}.authProvider`) === defaultChat.provider?.enterprise.id) {
return defaultChat.enterpriseProviderId; return defaultChat.provider!.enterprise.id;
} }
return defaultChat.providerId; return defaultChat.provider!.default.id;
} }
private state: IEntitlements; private state: IEntitlements;
@ -568,7 +566,7 @@ export class ChatEntitlementRequests extends Disposable {
} }
private async doResolveEntitlement(session: AuthenticationSession, token: CancellationToken): Promise<IEntitlements | undefined> { private async doResolveEntitlement(session: AuthenticationSession, token: CancellationToken): Promise<IEntitlements | undefined> {
if (ChatEntitlementRequests.providerId(this.configurationService) === defaultChat.enterpriseProviderId) { if (ChatEntitlementRequests.providerId(this.configurationService) === defaultChat.provider?.enterprise.id) {
this.logService.trace('[chat entitlement]: enterprise provider, assuming Enterprise plan'); this.logService.trace('[chat entitlement]: enterprise provider, assuming Enterprise plan');
return { entitlement: ChatEntitlement.Enterprise }; return { entitlement: ChatEntitlement.Enterprise };
} }
@ -857,9 +855,9 @@ export class ChatEntitlementRequests extends Disposable {
} }
} }
async signIn(options?: { useAlternateProvider?: boolean }) { async signIn(options?: { useSocialProvider?: string }) {
const providerId = ChatEntitlementRequests.providerId(this.configurationService); const providerId = ChatEntitlementRequests.providerId(this.configurationService);
const session = await this.authenticationService.createSession(providerId, defaultChat.providerScopes[0], options?.useAlternateProvider ? { provider: defaultChat.alternativeProviderId } : undefined); const session = await this.authenticationService.createSession(providerId, defaultChat.providerScopes[0], options?.useSocialProvider ? { provider: options.useSocialProvider } : undefined);
this.authenticationExtensionsService.updateAccountPreference(defaultChat.extensionId, providerId, session.account); this.authenticationExtensionsService.updateAccountPreference(defaultChat.extensionId, providerId, session.account);
this.authenticationExtensionsService.updateAccountPreference(defaultChat.chatExtensionId, providerId, session.account); this.authenticationExtensionsService.updateAccountPreference(defaultChat.chatExtensionId, providerId, session.account);

View File

@ -19,7 +19,14 @@ interface IGettingStartedContentProvider {
(): string; (): string;
} }
export const copilotSettingsMessage = localize({ key: 'settings', comment: ['{Locked="["}', '{Locked="]({0})"}', '{Locked="]({1})"}'] }, "{0} Copilot Free, Pro and Pro+ may show [public code]({1}) suggestions and we may use your data for product improvement. You can change these [settings]({2}) at any time.", product.defaultChatAgent?.providerName, product.defaultChatAgent?.publicCodeMatchesUrl, product.defaultChatAgent?.manageSettingsUrl); const defaultChat = {
documentationUrl: product.defaultChatAgent?.documentationUrl ?? '',
manageSettingsUrl: product.defaultChatAgent?.manageSettingsUrl ?? '',
provider: product.defaultChatAgent?.provider ?? { default: { name: '' } },
publicCodeMatchesUrl: product.defaultChatAgent?.publicCodeMatchesUrl ?? '',
};
export const copilotSettingsMessage = localize({ key: 'settings', comment: ['{Locked="["}', '{Locked="]({0})"}', '{Locked="]({1})"}'] }, "{0} Copilot Free, Pro and Pro+ may show [public code]({1}) suggestions and we may use your data for product improvement. You can change these [settings]({2}) at any time.", defaultChat.provider.default.name, defaultChat.publicCodeMatchesUrl, defaultChat.manageSettingsUrl);
class GettingStartedContentProviderRegistry { class GettingStartedContentProviderRegistry {
@ -217,7 +224,7 @@ export const startEntries: GettingStartedStartEntryContent = [
const Button = (title: string, href: string) => `[${title}](${href})`; const Button = (title: string, href: string) => `[${title}](${href})`;
const CopilotStepTitle = localize('gettingStarted.copilotSetup.title', "Use AI features with Copilot for free"); const CopilotStepTitle = localize('gettingStarted.copilotSetup.title', "Use AI features with Copilot for free");
const CopilotDescription = localize({ key: 'gettingStarted.copilotSetup.description', comment: ['{Locked="["}', '{Locked="]({0})"}'] }, "You can use [Copilot]({0}) to generate code across multiple files, fix errors, ask questions about your code and much more using natural language.", product.defaultChatAgent?.documentationUrl ?? ''); const CopilotDescription = localize({ key: 'gettingStarted.copilotSetup.description', comment: ['{Locked="["}', '{Locked="]({0})"}'] }, "You can use [Copilot]({0}) to generate code across multiple files, fix errors, ask questions about your code and much more using natural language.", defaultChat.documentationUrl ?? '');
const CopilotSignedOutButton = Button(localize('setupCopilotButton.signIn', "Set up Copilot"), `command:workbench.action.chat.triggerSetup`); const CopilotSignedOutButton = Button(localize('setupCopilotButton.signIn', "Set up Copilot"), `command:workbench.action.chat.triggerSetup`);
const CopilotSignedInButton = Button(localize('setupCopilotButton.setup', "Set up Copilot"), `command:workbench.action.chat.triggerSetup`); const CopilotSignedInButton = Button(localize('setupCopilotButton.setup', "Set up Copilot"), `command:workbench.action.chat.triggerSetup`);
const CopilotCompleteButton = Button(localize('setupCopilotButton.chatWithCopilot', "Chat with Copilot"), 'command:workbench.action.chat.open'); const CopilotCompleteButton = Button(localize('setupCopilotButton.chatWithCopilot', "Chat with Copilot"), 'command:workbench.action.chat.open');