Offer chat install experience for entitled users (#231287)

This commit is contained in:
Benjamin Pasero 2024-10-20 17:29:33 +02:00 committed by GitHub
parent d72a0f0af6
commit 42b425bc8e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 340 additions and 26 deletions

View File

@ -168,6 +168,5 @@
},
"css.format.spaceAroundSelectorSeparator": true,
"typescript.enablePromptUseWorkspaceTsdk": true,
"chat.commandCenter.enabled": true,
"eslint.useFlatConfig": true
}

View File

@ -194,6 +194,14 @@ export interface IProductConfiguration {
readonly chatParticipantRegistry?: string;
readonly emergencyAlertUrl?: string;
readonly defaultChatAgent?: {
readonly extensionId: string;
readonly name: string;
readonly icon: string;
readonly documentationUrl: string;
readonly gettingStartedCommand: string;
};
}
export interface ITunnelApplicationConfig {

View File

@ -27,6 +27,8 @@ import { CancellationToken } from '../../../../base/common/cancellation.js';
import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
import { isWeb } from '../../../../base/common/platform.js';
// TODO@bpasero remove this experiment eventually
const accountsBadgeConfigKey = 'workbench.accounts.experimental.showEntitlements';
type EntitlementEnablementClassification = {

View File

@ -18,18 +18,23 @@ import { localize, localize2 } from '../../../../../nls.js';
import { IActionViewItemService } from '../../../../../platform/actions/browser/actionViewItemService.js';
import { DropdownWithPrimaryActionViewItem } from '../../../../../platform/actions/browser/dropdownWithPrimaryActionViewItem.js';
import { Action2, MenuId, MenuItemAction, MenuRegistry, registerAction2, SubmenuItemAction } from '../../../../../platform/actions/common/actions.js';
import { ICommandService } from '../../../../../platform/commands/common/commands.js';
import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js';
import { IsLinuxContext, IsWindowsContext } from '../../../../../platform/contextkey/common/contextkeys.js';
import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js';
import { IOpenerService } from '../../../../../platform/opener/common/opener.js';
import { IProductService } from '../../../../../platform/product/common/productService.js';
import { ProgressLocation } from '../../../../../platform/progress/common/progress.js';
import { IQuickInputButton, IQuickInputService, IQuickPickItem, IQuickPickSeparator } from '../../../../../platform/quickinput/common/quickInput.js';
import { ToggleTitleBarConfigAction } from '../../../../browser/parts/titlebar/titlebarActions.js';
import { IWorkbenchContribution } from '../../../../common/contributions.js';
import { IEditorGroupsService } from '../../../../services/editor/common/editorGroupsService.js';
import { ACTIVE_GROUP, IEditorService } from '../../../../services/editor/common/editorService.js';
import { IViewsService } from '../../../../services/views/common/viewsService.js';
import { IExtensionsWorkbenchService } from '../../../extensions/common/extensions.js';
import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js';
import { CONTEXT_CHAT_ENABLED, CONTEXT_CHAT_INPUT_CURSOR_AT_TOP, CONTEXT_CHAT_LOCATION, CONTEXT_IN_CHAT_INPUT, CONTEXT_IN_CHAT_SESSION, CONTEXT_IN_QUICK_CHAT } from '../../common/chatContextKeys.js';
import { CONTEXT_CHAT_ENABLED, CONTEXT_CHAT_INPUT_CURSOR_AT_TOP, CONTEXT_CHAT_INSTALL_ENTITLED, CONTEXT_CHAT_LOCATION, CONTEXT_CHAT_PANEL_PARTICIPANT_REGISTERED, CONTEXT_IN_CHAT_INPUT, CONTEXT_IN_CHAT_SESSION, CONTEXT_IN_QUICK_CHAT } from '../../common/chatContextKeys.js';
import { extractAgentAndCommand } from '../../common/chatParserTypes.js';
import { IChatDetail, IChatService } from '../../common/chatService.js';
import { IChatRequestViewModel, IChatResponseViewModel, isRequestVM } from '../../common/chatViewModel.js';
@ -40,6 +45,8 @@ import { ChatEditorInput } from '../chatEditorInput.js';
import { ChatViewPane } from '../chatViewPane.js';
import { convertBufferToScreenshotVariable } from '../contrib/screenshot.js';
import { clearChatEditor } from './chatClear.js';
import product from '../../../../../platform/product/common/product.js';
import { URI } from '../../../../../base/common/uri.js';
import { IHostService } from '../../../../services/host/browser/host.js';
export const CHAT_CATEGORY = localize2('chat.category', 'Chat');
@ -70,6 +77,14 @@ export interface IChatViewOpenRequestEntry {
response: string;
}
const defaultChat = {
extensionId: product.defaultChatAgent?.extensionId ?? '',
name: product.defaultChatAgent?.name ?? '',
icon: Codicon[product.defaultChatAgent?.icon as keyof typeof Codicon ?? 'commentDiscussion'],
documentationUrl: product.defaultChatAgent?.documentationUrl ?? '',
gettingStartedCommand: product.defaultChatAgent?.gettingStartedCommand ?? '',
};
class OpenChatGlobalAction extends Action2 {
static readonly TITLE = localize2('openChat', "Open Chat");
@ -78,8 +93,9 @@ class OpenChatGlobalAction extends Action2 {
super({
id: CHAT_OPEN_ACTION_ID,
title: OpenChatGlobalAction.TITLE,
icon: Codicon.commentDiscussion,
icon: defaultChat.icon,
f1: true,
precondition: CONTEXT_CHAT_PANEL_PARTICIPANT_REGISTERED,
category: CHAT_CATEGORY,
keybinding: {
weight: KeybindingWeight.WorkbenchContrib,
@ -422,6 +438,10 @@ export function registerChatActions() {
widgetService.lastFocusedWidget?.focusInput();
}
});
registerAction2(InstallChatWithPromptAction);
registerAction2(InstallChatWithoutPromptAction);
registerAction2(LearnMoreChatAction);
}
export function stringifyItem(item: IChatRequestViewModel | IChatResponseViewModel, includeName = true): string {
@ -438,14 +458,25 @@ export function stringifyItem(item: IChatRequestViewModel | IChatResponseViewMod
MenuRegistry.appendMenuItem(MenuId.CommandCenter, {
submenu: MenuId.ChatCommandCenter,
title: localize('title4', "Chat"),
icon: Codicon.commentDiscussion,
when: ContextKeyExpr.and(CONTEXT_CHAT_ENABLED, ContextKeyExpr.has('config.chat.commandCenter.enabled')),
icon: defaultChat.icon,
when: ContextKeyExpr.and(
ContextKeyExpr.has('config.chat.commandCenter.enabled'),
ContextKeyExpr.or(CONTEXT_CHAT_PANEL_PARTICIPANT_REGISTERED, CONTEXT_CHAT_INSTALL_ENTITLED)
),
order: 10001,
});
registerAction2(class ToggleChatControl extends ToggleTitleBarConfigAction {
constructor() {
super('chat.commandCenter.enabled', localize('toggle.chatControl', 'Chat Controls'), localize('toggle.chatControlsDescription', "Toggle visibility of the Chat Controls in title bar"), 3, false, ContextKeyExpr.and(CONTEXT_CHAT_ENABLED, ContextKeyExpr.has('config.window.commandCenter')));
super(
'chat.commandCenter.enabled',
localize('toggle.chatControl', 'Chat Controls'),
localize('toggle.chatControlsDescription', "Toggle visibility of the Chat Controls in title bar"), 3, false,
ContextKeyExpr.and(
ContextKeyExpr.has('config.window.commandCenter'),
ContextKeyExpr.or(CONTEXT_CHAT_PANEL_PARTICIPANT_REGISTERED, CONTEXT_CHAT_INSTALL_ENTITLED)
)
);
}
});
@ -463,25 +494,22 @@ export class ChatCommandCenterRendering implements IWorkbenchContribution {
this._store.add(actionViewItemService.register(MenuId.CommandCenter, MenuId.ChatCommandCenter, (action, options) => {
const agent = agentService.getDefaultAgent(ChatAgentLocation.Panel);
if (!agent?.metadata.themeIcon) {
return undefined;
}
if (!(action instanceof SubmenuItemAction)) {
return undefined;
}
const dropdownAction = toAction({
id: agent.id,
id: 'chat.commandCenter.more',
label: localize('more', "More..."),
run() { }
});
const chatExtensionInstalled = agentService.getAgents().some(agent => agent.isDefault);
const primaryAction = instantiationService.createInstance(MenuItemAction, {
id: CHAT_OPEN_ACTION_ID,
title: OpenChatGlobalAction.TITLE,
icon: agent.metadata.themeIcon,
id: chatExtensionInstalled ? CHAT_OPEN_ACTION_ID : InstallChatWithPromptAction.ID,
title: chatExtensionInstalled ? OpenChatGlobalAction.TITLE : InstallChatWithPromptAction.TITLE,
icon: defaultChat.icon,
}, undefined, undefined, undefined, undefined);
return instantiationService.createInstance(
@ -501,3 +529,97 @@ export class ChatCommandCenterRendering implements IWorkbenchContribution {
this._store.dispose();
}
}
abstract class BaseInstallChatAction extends Action2 {
protected abstract getJustification(): string | undefined;
override async run(accessor: ServicesAccessor): Promise<void> {
const extensionsWorkbenchService = accessor.get(IExtensionsWorkbenchService);
const commandService = accessor.get(ICommandService);
const productService = accessor.get(IProductService);
await extensionsWorkbenchService.install(defaultChat.extensionId, {
justification: this.getJustification(),
enable: true,
installPreReleaseVersion: productService.quality !== 'stable'
}, ProgressLocation.Notification);
await commandService.executeCommand(CHAT_OPEN_ACTION_ID);
}
}
class InstallChatWithPromptAction extends BaseInstallChatAction {
static readonly ID = 'workbench.action.chat.installWithPrompt';
static readonly TITLE = localize2('installChat', "Install {0}", defaultChat.name);
constructor() {
super({
id: InstallChatWithPromptAction.ID,
title: InstallChatWithPromptAction.TITLE,
icon: defaultChat.icon,
category: CHAT_CATEGORY
});
}
protected getJustification(): string {
return localize('installChatGlobalAction.justification', "AI support requires this extension.");
}
}
class InstallChatWithoutPromptAction extends BaseInstallChatAction {
static readonly ID = 'workbench.action.chat.installWithoutPrompt';
static readonly TITLE = localize2('installChat', "Install {0}", defaultChat.name);
constructor() {
super({
id: InstallChatWithoutPromptAction.ID,
title: InstallChatWithoutPromptAction.TITLE,
category: CHAT_CATEGORY,
menu: {
id: MenuId.ChatCommandCenter,
group: 'a_atfirst',
order: 1,
when: CONTEXT_CHAT_PANEL_PARTICIPANT_REGISTERED.negate()
}
});
}
protected getJustification(): string | undefined {
return undefined;
}
}
class LearnMoreChatAction extends Action2 {
static readonly ID = 'workbench.action.chat.learnMore';
static readonly TITLE = localize2('learnMore', "Learn More");
constructor() {
super({
id: LearnMoreChatAction.ID,
title: LearnMoreChatAction.TITLE,
category: CHAT_CATEGORY,
menu: [{
id: MenuId.ChatCommandCenter,
group: 'a_atfirst',
order: 2,
when: CONTEXT_CHAT_PANEL_PARTICIPANT_REGISTERED.negate()
}, {
id: MenuId.ChatCommandCenter,
group: 'z_atlast',
order: 1,
when: CONTEXT_CHAT_PANEL_PARTICIPANT_REGISTERED
}]
});
}
override async run(accessor: ServicesAccessor): Promise<void> {
const openerService = accessor.get(IOpenerService);
if (defaultChat.documentationUrl) {
openerService.open(URI.parse(defaultChat.documentationUrl));
}
}
}

View File

@ -36,7 +36,7 @@ import { SearchView } from '../../../search/browser/searchView.js';
import { ISymbolQuickPickItem, SymbolsQuickAccessProvider } from '../../../search/browser/symbolsQuickAccess.js';
import { SearchContext } from '../../../search/common/constants.js';
import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js';
import { CONTEXT_CHAT_LOCATION, CONTEXT_IN_CHAT_INPUT } from '../../common/chatContextKeys.js';
import { CONTEXT_CHAT_ENABLED, CONTEXT_CHAT_LOCATION, CONTEXT_IN_CHAT_INPUT } from '../../common/chatContextKeys.js';
import { IChatEditingService } from '../../common/chatEditingService.js';
import { IChatRequestVariableEntry } from '../../common/chatModel.js';
import { ChatRequestAgentPart } from '../../common/chatParserTypes.js';
@ -166,7 +166,7 @@ class AttachFileAction extends Action2 {
title: localize2('workbench.action.chat.attachFile.label', "Add File to Chat"),
category: CHAT_CATEGORY,
f1: false,
precondition: ActiveEditorContext.isEqualTo('workbench.editors.files.textFileEditor'),
precondition: ContextKeyExpr.and(CONTEXT_CHAT_ENABLED, ActiveEditorContext.isEqualTo('workbench.editors.files.textFileEditor')),
menu: {
id: MenuId.ChatCommandCenter,
group: 'a_chat',
@ -197,7 +197,7 @@ class AttachSelectionAction extends Action2 {
title: localize2('workbench.action.chat.attachSelection.label', "Add Selection to Chat"),
category: CHAT_CATEGORY,
f1: false,
precondition: ActiveEditorContext.isEqualTo('workbench.editors.files.textFileEditor'),
precondition: ContextKeyExpr.and(CONTEXT_CHAT_ENABLED, ActiveEditorContext.isEqualTo('workbench.editors.files.textFileEditor')),
menu: {
id: MenuId.ChatCommandCenter,
group: 'a_chat',

View File

@ -19,10 +19,9 @@ import { InstantiationType, registerSingleton } from '../../../../platform/insta
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { Registry } from '../../../../platform/registry/common/platform.js';
import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js';
import { WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js';
import { EditorExtensions, IEditorFactoryRegistry } from '../../../common/editor.js';
import { IEditorResolverService, RegisteredEditorPriority } from '../../../services/editor/common/editorResolverService.js';
import { LifecyclePhase } from '../../../services/lifecycle/common/lifecycle.js';
import { ChatAgentLocation, ChatAgentNameService, ChatAgentService, IChatAgentNameService, IChatAgentService } from '../common/chatAgents.js';
import { CodeMapperService, ICodeMapperService } from '../common/chatCodeMapperService.js';
import '../common/chatColors.js';
@ -114,9 +113,8 @@ configurationRegistry.registerConfiguration({
},
'chat.commandCenter.enabled': {
type: 'boolean',
tags: ['experimental'],
markdownDescription: nls.localize('chat.commandCenter.enabled', "Controls whether the command center shows a menu for chat actions (requires {0}).", '`#window.commandCenter#`'),
default: false
default: true
},
'chat.editing.alwaysSaveWithGeneratedChanges': {
type: 'boolean',
@ -196,6 +194,8 @@ AccessibleViewRegistry.register(new QuickChatAccessibilityHelp());
class ChatSlashStaticSlashCommandsContribution extends Disposable {
static readonly ID = 'workbench.contrib.chatSlashStaticSlashCommands';
constructor(
@IChatSlashCommandService slashCommandService: IChatSlashCommandService,
@ICommandService commandService: ICommandService,
@ -286,11 +286,10 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable {
}));
}
}
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
registerWorkbenchContribution2(ChatResolverContribution.ID, ChatResolverContribution, WorkbenchPhase.BlockStartup);
workbenchContributionsRegistry.registerWorkbenchContribution(ChatSlashStaticSlashCommandsContribution, LifecyclePhase.Eventually);
Registry.as<IEditorFactoryRegistry>(EditorExtensions.EditorFactory).registerEditorSerializer(ChatEditorInput.TypeID, ChatEditorInputSerializer);
registerWorkbenchContribution2(ChatResolverContribution.ID, ChatResolverContribution, WorkbenchPhase.BlockStartup);
registerWorkbenchContribution2(ChatSlashStaticSlashCommandsContribution.ID, ChatSlashStaticSlashCommandsContribution, WorkbenchPhase.Eventually);
registerWorkbenchContribution2(ChatExtensionPointHandler.ID, ChatExtensionPointHandler, WorkbenchPhase.BlockStartup);
registerWorkbenchContribution2(LanguageModelToolsExtensionPointHandler.ID, LanguageModelToolsExtensionPointHandler, WorkbenchPhase.BlockRestore);
registerWorkbenchContribution2(ChatCompatibilityNotifier.ID, ChatCompatibilityNotifier, WorkbenchPhase.Eventually);

View File

@ -7,6 +7,7 @@ import { coalesce, isNonEmptyArray } from '../../../../base/common/arrays.js';
import { Codicon } from '../../../../base/common/codicons.js';
import { toErrorMessage } from '../../../../base/common/errorMessage.js';
import { Event } from '../../../../base/common/event.js';
import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';
import { Disposable, DisposableMap, DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
import * as strings from '../../../../base/common/strings.js';
import { localize, localize2 } from '../../../../nls.js';
@ -289,6 +290,16 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
storageId: viewContainerId,
hideIfEmpty: true,
order: 100,
openCommandActionDescriptor: {
id: viewContainerId,
keybindings: {
primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyI,
mac: {
primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KeyI
}
},
order: 100
},
}, ViewContainerLocation.Sidebar);
return viewContainer;

View File

@ -37,3 +37,5 @@ export const CONTEXT_IN_QUICK_CHAT = new RawContextKey<boolean>('quickChatHasFoc
export const CONTEXT_CHAT_HAS_FILE_ATTACHMENTS = new RawContextKey<boolean>('chatHasFileAttachments', false, { type: 'boolean', description: localize('chatHasFileAttachments', "True when the chat has file attachments.") });
export const CONTEXT_LANGUAGE_MODELS_ARE_USER_SELECTABLE = new RawContextKey<boolean>('chatModelsAreUserSelectable', false, { type: 'boolean', description: localize('chatModelsAreUserSelectable', "True when the chat model can be selected manually by the user.") });
export const CONTEXT_CHAT_INSTALL_ENTITLED = new RawContextKey<boolean>('chatInstallEntitled', false, { type: 'boolean', description: localize('chatInstallEntitled', "True when the user is entitled for chat installation.") });

View File

@ -0,0 +1,161 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js';
import { Disposable, DisposableStore, toDisposable } from '../../../../base/common/lifecycle.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
import { AuthenticationSession, IAuthenticationService } from '../../../services/authentication/common/authentication.js';
import { IProductService } from '../../../../platform/product/common/productService.js';
import { IExtensionManagementService } from '../../../../platform/extensionManagement/common/extensionManagement.js';
import { ExtensionIdentifier } from '../../../../platform/extensions/common/extensions.js';
import { IExtensionService } from '../../../services/extensions/common/extensions.js';
import { IRequestService, asText } from '../../../../platform/request/common/request.js';
import { CancellationTokenSource } from '../../../../base/common/cancellation.js';
import { CONTEXT_CHAT_INSTALL_ENTITLED } from './chatContextKeys.js';
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
// TODO@bpasero revisit this flow
type ChatInstallEntitlementEnablementClassification = {
entitled: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Flag indicating if the user is chat install entitled' };
owner: 'bpasero';
comment: 'Reporting if the user is chat install entitled';
};
type ChatInstallEntitlementEnablementEvent = {
entitled: boolean;
};
class ChatInstallEntitlementContribution extends Disposable implements IWorkbenchContribution {
private static readonly CHAT_EXTENSION_INSTALLED_KEY = 'chat.extensionInstalled';
private readonly chatInstallEntitledContextKey = CONTEXT_CHAT_INSTALL_ENTITLED.bindTo(this.contextService);
private readonly listeners = this._register(new DisposableStore());
private didResolveEntitlement = false;
constructor(
@IContextKeyService private readonly contextService: IContextKeyService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IAuthenticationService private readonly authenticationService: IAuthenticationService,
@IProductService private readonly productService: IProductService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
@IExtensionService private readonly extensionService: IExtensionService,
@IRequestService private readonly requestService: IRequestService,
@IStorageService private readonly storageService: IStorageService
) {
super();
if (!this.productService.gitHubEntitlement) {
return;
}
this.init();
}
private async init(): Promise<void> {
const extensions = await this.extensionManagementService.getInstalled();
const installed = extensions.find(value => ExtensionIdentifier.equals(value.identifier.id, this.productService.gitHubEntitlement?.extensionId));
if (!installed) {
this.registerListeners();
} else {
this.disableEntitlement(true);
}
}
private registerListeners(): void {
this.listeners.add(this.extensionService.onDidChangeExtensions(result => {
for (const extension of result.added) {
if (ExtensionIdentifier.equals(this.productService.gitHubEntitlement?.extensionId, extension.identifier)) {
this.disableEntitlement(true);
return;
}
}
}));
this.listeners.add(this.authenticationService.onDidChangeSessions(async e => {
if (e.providerId === this.productService.gitHubEntitlement?.providerId && e.event.added?.length) {
await this.resolveEntitlement(e.event.added[0]);
} else if (e.providerId === this.productService.gitHubEntitlement?.providerId && e.event.removed?.length) {
this.disableEntitlement(false);
}
}));
this.listeners.add(this.authenticationService.onDidRegisterAuthenticationProvider(async e => {
if (e.id === this.productService.gitHubEntitlement?.providerId) {
this.resolveEntitlement((await this.authenticationService.getSessions(e.id))[0]);
}
}));
}
private async resolveEntitlement(session: AuthenticationSession | undefined) {
if (!session) {
return;
}
const installedExtensions = await this.extensionManagementService.getInstalled();
const installed = installedExtensions.find(value => ExtensionIdentifier.equals(value.identifier.id, this.productService.gitHubEntitlement?.extensionId));
if (installed) {
this.disableEntitlement(true);
return;
}
const entitled = await this.doResolveEntitlement(session);
this.chatInstallEntitledContextKey.set(entitled);
}
private async doResolveEntitlement(session: AuthenticationSession): Promise<boolean> {
if (this.didResolveEntitlement) {
return false;
}
const cts = new CancellationTokenSource();
this._register(toDisposable(() => cts.dispose(true)));
const context = await this.requestService.request({
type: 'GET',
url: this.productService.gitHubEntitlement!.entitlementUrl,
headers: {
'Authorization': `Bearer ${session.accessToken}`
}
}, cts.token);
if (context.res.statusCode && context.res.statusCode !== 200) {
return false;
}
const result = await asText(context);
if (!result) {
return false;
}
let parsedResult: any;
try {
parsedResult = JSON.parse(result);
} catch (err) {
return false; //ignore
}
this.didResolveEntitlement = true;
const entitled = Boolean(parsedResult[this.productService.gitHubEntitlement!.enablementKey]);
this.telemetryService.publicLog2<ChatInstallEntitlementEnablementEvent, ChatInstallEntitlementEnablementClassification>('chatInstallEntitlement', { entitled });
return entitled;
}
private disableEntitlement(isExtensionInstalled: boolean): void {
if (isExtensionInstalled) {
this.storageService.store(ChatInstallEntitlementContribution.CHAT_EXTENSION_INSTALLED_KEY, true, StorageScope.PROFILE, StorageTarget.MACHINE);
}
this.chatInstallEntitledContextKey.set(false);
this.listeners.dispose();
}
}
registerWorkbenchContribution2('workbench.chat.installEntitlement', ChatInstallEntitlementContribution, WorkbenchPhase.BlockRestore);

View File

@ -395,6 +395,15 @@ class ConfigurationTelemetryContribution extends Disposable implements IWorkbenc
}>('window.commandCenter', { settingValue: this.getValueToReport(key, target), source });
return;
case 'chat.commandCenter.enabled':
this.telemetryService.publicLog2<UpdatedSettingEvent, {
owner: 'bpasero';
comment: 'This is used to know if command center chat menu is enabled or not';
settingValue: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'value of the setting' };
source: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'source of the setting' };
}>('chat.commandCenter.enabled', { settingValue: this.getValueToReport(key, target), source });
return;
case 'window.customTitleBarVisibility':
this.telemetryService.publicLog2<UpdatedSettingEvent, {
owner: 'benibenj';

View File

@ -171,6 +171,7 @@ import './contrib/remoteTunnel/electron-sandbox/remoteTunnel.contribution.js';
// Chat
import './contrib/chat/electron-sandbox/chat.contribution.js';
import './contrib/inlineChat/electron-sandbox/inlineChat.contribution.js';
import './contrib/chat/common/chatInstallEntitlement.contribution.js';
// Encryption
import './contrib/encryption/electron-sandbox/encryption.contribution.js';