diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts index cca372c610304..de160c8c26315 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts @@ -534,9 +534,8 @@ MenuRegistry.appendMenuItem(MenuId.CommandCenter, { when: ContextKeyExpr.and( ContextKeyExpr.has('config.chat.commandCenter.enabled'), ContextKeyExpr.or( - ChatContextKeys.Setup.installed, - ChatContextKeys.Setup.entitled, ContextKeyExpr.has('config.chat.experimental.offerSetup'), + ChatContextKeys.Setup.installed, ChatContextKeys.panelParticipantRegistered ) ), @@ -553,7 +552,6 @@ registerAction2(class ToggleCopilotControl extends ToggleTitleBarConfigAction { ContextKeyExpr.has('config.window.commandCenter'), ContextKeyExpr.or( ChatContextKeys.Setup.installed, - ChatContextKeys.Setup.entitled, ContextKeyExpr.has('config.chat.experimental.offerSetup'), ChatContextKeys.panelParticipantRegistered ) diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingService.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingService.ts index 34b24c1dbb8e4..458687df09a9c 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingService.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingService.ts @@ -157,7 +157,7 @@ export class ChatEditingService extends Disposable implements IChatEditingServic void this._editingSessionFileLimitPromise; const sessionIdToRestore = storageService.get(STORAGE_KEY_EDITING_SESSION, StorageScope.WORKSPACE); - if (isString(sessionIdToRestore)) { + if (isString(sessionIdToRestore) && this._chatService.getOrRestoreSession(sessionIdToRestore)) { this._restoringEditingSession = this.startOrContinueEditingSession(sessionIdToRestore); this._restoringEditingSession.finally(() => { this._restoringEditingSession = undefined; diff --git a/src/vs/workbench/contrib/chat/browser/chatSetup.ts b/src/vs/workbench/contrib/chat/browser/chatSetup.ts index 27c17e0617254..d31113c0d6b19 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSetup.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSetup.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import './media/chatViewSetup.css'; -import { $, addDisposableListener, EventType, getActiveElement, setVisibility } from '../../../../base/browser/dom.js'; +import { $, getActiveElement, setVisibility } from '../../../../base/browser/dom.js'; import { Button, ButtonWithDropdown } from '../../../../base/browser/ui/button/button.js'; import { renderIcon } from '../../../../base/browser/ui/iconLabel/iconLabels.js'; import { IAction, toAction } from '../../../../base/common/actions.js'; @@ -37,7 +37,7 @@ import { Registry } from '../../../../platform/registry/common/platform.js'; import { asText, IRequestService } from '../../../../platform/request/common/request.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; -import { defaultButtonStyles, defaultCheckboxStyles } from '../../../../platform/theme/browser/defaultStyles.js'; +import { defaultButtonStyles } from '../../../../platform/theme/browser/defaultStyles.js'; import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; import { IWorkbenchContribution } from '../../../common/contributions.js'; import { IViewDescriptorService, ViewContainerLocation } from '../../../common/views.js'; @@ -55,7 +55,6 @@ import { ChatViewId, EditsViewId, ensureSideBarChatViewSize, IChatWidget, showCh import { CHAT_EDITING_SIDEBAR_PANEL_ID, CHAT_SIDEBAR_PANEL_ID } from './chatViewPane.js'; import { ChatViewsWelcomeExtensions, IChatViewsWelcomeContributionRegistry } from './viewsWelcome/chatViewsWelcome.js'; import { IChatQuotasService } from './chatQuotasService.js'; -import { Checkbox } from '../../../../base/browser/ui/toggle/toggle.js'; import { mainWindow } from '../../../../base/browser/window.js'; const defaultChat = { @@ -65,7 +64,6 @@ const defaultChat = { termsStatementUrl: product.defaultChatAgent?.termsStatementUrl ?? '', privacyStatementUrl: product.defaultChatAgent?.privacyStatementUrl ?? '', skusDocumentationUrl: product.defaultChatAgent?.skusDocumentationUrl ?? '', - publicCodeMatchesUrl: product.defaultChatAgent?.publicCodeMatchesUrl ?? '', providerId: product.defaultChatAgent?.providerId ?? '', providerName: product.defaultChatAgent?.providerName ?? '', providerScopes: product.defaultChatAgent?.providerScopes ?? [[]], @@ -88,8 +86,6 @@ enum ChatEntitlement { Pro } -const ASK_FOR_PUBLIC_CODE_MATCHES = false; // TODO@bpasero revisit this - //#region Contribution const TRIGGER_SETUP_COMMAND_ID = 'workbench.action.chat.triggerSetup'; @@ -158,10 +154,7 @@ export class ChatSetupContribution extends Disposable implements IWorkbenchContr f1: true, precondition: ContextKeyExpr.and( ChatContextKeys.Setup.installed.negate(), - ContextKeyExpr.or( - ChatContextKeys.Setup.entitled, - ContextKeyExpr.has('config.chat.experimental.offerSetup') - ) + ContextKeyExpr.has('config.chat.experimental.offerSetup') ), menu: { id: MenuId.ChatCommandCenter, @@ -183,9 +176,9 @@ export class ChatSetupContribution extends Disposable implements IWorkbenchContr showCopilotView(viewsService, layoutService); ensureSideBarChatViewSize(400, viewDescriptorService, layoutService); - if (startSetup === true && !ASK_FOR_PUBLIC_CODE_MATCHES) { + if (startSetup === true) { const controller = that.controller.value; - controller.setup({ publicCodeSuggestions: true }); + controller.setup(); } configurationService.updateValue('chat.commandCenter.enabled', true); @@ -205,10 +198,7 @@ export class ChatSetupContribution extends Disposable implements IWorkbenchContr category: CHAT_CATEGORY, precondition: ContextKeyExpr.and( ChatContextKeys.Setup.installed.negate(), - ContextKeyExpr.or( - ChatContextKeys.Setup.entitled, - ContextKeyExpr.has('config.chat.experimental.offerSetup') - ) + ContextKeyExpr.has('config.chat.experimental.offerSetup') ), menu: { id: MenuId.ChatCommandCenter, @@ -521,10 +511,10 @@ class ChatSetupRequests extends Disposable { return this.resolveEntitlement(session, CancellationToken.None); } - async signUpLimited(session: AuthenticationSession, options: { publicCodeSuggestions: boolean }): Promise { + async signUpLimited(session: AuthenticationSession): Promise { const body = { restricted_telemetry: 'disabled', - public_code_suggestions: options.publicCodeSuggestions ? 'enabled' : 'disabled' + public_code_suggestions: 'enabled' }; const response = await this.request(defaultChat.entitlementSignupLimitedUrl, 'POST', body, session, CancellationToken.None); @@ -637,7 +627,7 @@ class ChatSetupController extends Disposable { this._onDidChange.fire(); } - async setup(options: { publicCodeSuggestions: boolean }): Promise { + async setup(): Promise { const title = localize('setupChatProgress', "Getting Copilot ready..."); const badge = this.activityService.showViewContainerActivity(isCopilotEditsViewActive(this.viewsService) ? CHAT_EDITING_SIDEBAR_PANEL_ID : CHAT_SIDEBAR_PANEL_ID, { badge: new ProgressBadge(() => title), @@ -649,14 +639,16 @@ class ChatSetupController extends Disposable { location: ProgressLocation.Window, command: TRIGGER_SETUP_COMMAND_ID, title, - }, () => this.doSetup(options)); + }, () => this.doSetup()); } finally { badge.dispose(); } } - private async doSetup(options: { publicCodeSuggestions: boolean }): Promise { + private async doSetup(): Promise { this.context.suspend(); // reduces flicker + + let focusChatInput = false; try { let session: AuthenticationSession | undefined; let entitlement: ChatEntitlement | undefined; @@ -680,13 +672,22 @@ class ChatSetupController extends Disposable { } } + const activeElement = getActiveElement(); + // Install this.setStep(ChatSetupStep.Installing); - await this.install(session, entitlement ?? this.context.state.entitlement, options); + await this.install(session, entitlement ?? this.context.state.entitlement); + + const currentActiveElement = getActiveElement(); + focusChatInput = activeElement === currentActiveElement || currentActiveElement === mainWindow.document.body; } finally { this.setStep(ChatSetupStep.Initial); this.context.resume(); } + + if (focusChatInput) { + (await showCopilotView(this.viewsService, this.layoutService))?.focusInput(); + } } private async signIn(): Promise<{ session: AuthenticationSession | undefined; entitlement: ChatEntitlement | undefined }> { @@ -694,6 +695,7 @@ class ChatSetupController extends Disposable { let entitlement: ChatEntitlement | undefined; try { showCopilotView(this.viewsService, this.layoutService); + session = await this.authenticationService.createSession(defaultChat.providerId, defaultChat.providerScopes[0]); entitlement = await this.requests.forceResolveEntitlement(session); } catch (error) { @@ -707,9 +709,8 @@ class ChatSetupController extends Disposable { return { session, entitlement }; } - private async install(session: AuthenticationSession, entitlement: ChatEntitlement, options: { publicCodeSuggestions: boolean }): Promise { + private async install(session: AuthenticationSession, entitlement: ChatEntitlement,): Promise { const signedIn = !!session; - const activeElement = getActiveElement(); let installResult: 'installed' | 'cancelled' | 'failedInstall' | undefined = undefined; const wasInstalled = this.context.state.installed; @@ -718,7 +719,7 @@ class ChatSetupController extends Disposable { showCopilotView(this.viewsService, this.layoutService); if (entitlement !== ChatEntitlement.Limited && entitlement !== ChatEntitlement.Pro && entitlement !== ChatEntitlement.Unavailable) { - didSignUp = await this.requests.signUpLimited(session, options); + didSignUp = await this.requests.signUpLimited(session); } await this.extensionsWorkbenchService.install(defaultChat.extensionId, { @@ -747,11 +748,6 @@ class ChatSetupController extends Disposable { } this.telemetryService.publicLog2('commandCenter.chatInstall', { installResult, signedIn }); - - const currentActiveElement = getActiveElement(); - if (activeElement === currentActiveElement || currentActiveElement === mainWindow.document.body) { - (await showCopilotView(this.viewsService, this.layoutService))?.focusInput(); - } } } @@ -802,18 +798,14 @@ class ChatSetupWelcomeContent extends Disposable { } // Limited SKU - const limitedSkuHeader = localize({ key: 'limitedSkuHeader', comment: ['{Locked="[]({0})"}'] }, "$(sparkle-filled) We now offer [Copilot for free]({0}).", defaultChat.skusDocumentationUrl); + const limitedSkuHeader = localize({ key: 'limitedSkuHeader', comment: ['{Locked="[]({0})"}'] }, "$(sparkle-filled) We now offer [Copilot for free]({0}) with 50 chat messages and 2000 code completions per month.", defaultChat.skusDocumentationUrl); const limitedSkuHeaderContainer = this.element.appendChild($('p')); limitedSkuHeaderContainer.appendChild(this._register(markdown.render(new MarkdownString(limitedSkuHeader, { isTrusted: true, supportThemeIcons: true }))).element); - const publicCodeSuggestionsLabel = localize('detectionLabel', "Allow code suggestions that [match public code]({0})", defaultChat.publicCodeMatchesUrl); - const { container: publicCodeSuggestionsContainer, checkbox: publicCodeSuggestionsCheckbox } = this.createCheckBox(publicCodeSuggestionsLabel, true, markdown); - // Terms const terms = localize({ key: 'termsLabel', comment: ['{Locked="["}', '{Locked="]({0})"}', '{Locked="]({1})"}'] }, "By continuing, you agree to our [Terms]({0}) and [Privacy Policy]({1}).", defaultChat.termsStatementUrl, defaultChat.privacyStatementUrl); const termsContainer = this.element.appendChild($('p')); termsContainer.classList.add('terms-container'); - termsContainer.classList.toggle('is-standalone', !ASK_FOR_PUBLIC_CODE_MATCHES); termsContainer.appendChild(this._register(markdown.render(new MarkdownString(terms, { isTrusted: true }))).element); // Setup Button @@ -833,30 +825,13 @@ class ChatSetupWelcomeContent extends Disposable { supportIcons: true, ...defaultButtonStyles })); - this._register(button.onDidClick(() => this.controller.setup({ publicCodeSuggestions: ASK_FOR_PUBLIC_CODE_MATCHES ? publicCodeSuggestionsCheckbox.checked : true }))); + this._register(button.onDidClick(() => this.controller.setup())); // Update based on model state - this._register(Event.runAndSubscribe(this.controller.onDidChange, () => this.update(limitedSkuHeaderContainer, button, [publicCodeSuggestionsContainer], [publicCodeSuggestionsCheckbox]))); + this._register(Event.runAndSubscribe(this.controller.onDidChange, () => this.update(limitedSkuHeaderContainer, button))); } - private createCheckBox(label: string, checked: boolean, markdown: MarkdownRenderer): { container: HTMLElement; checkbox: Checkbox } { - const container = this.element.appendChild($('p.checkbox-container')); - const checkbox = this._register(new Checkbox(label, checked, defaultCheckboxStyles)); - container.appendChild(checkbox.domNode); - - const checkboxLabel = container.appendChild(this._register(markdown.render(new MarkdownString(label, { isTrusted: true, supportThemeIcons: true }), { inline: true, className: 'checkbox-label' })).element); - this._register(addDisposableListener(checkboxLabel, EventType.CLICK, e => { - if (checkbox?.enabled && (e.target as HTMLElement).tagName !== 'A') { - checkbox.checked = !checkbox.checked; - checkbox.focus(); - } - })); - - return { container, checkbox }; - } - - private update(limitedSkuHeaderContainer: HTMLElement, button: Button | ButtonWithDropdown, limitedCheckboxContainers: HTMLElement[], limitedCheckboxes: Checkbox[]): void { - const showLimitedCheckboxes = ASK_FOR_PUBLIC_CODE_MATCHES ? this.context.state.entitlement !== ChatEntitlement.Limited && this.context.state.entitlement !== ChatEntitlement.Pro && this.context.state.entitlement !== ChatEntitlement.Unavailable : false; + private update(limitedSkuHeaderContainer: HTMLElement, button: Button | ButtonWithDropdown): void { let showLimitedSkuHeader: boolean; let buttonLabel: string; @@ -882,27 +857,15 @@ class ChatSetupWelcomeContent extends Disposable { } switch (this.controller.step) { - case ChatSetupStep.Initial: - for (const checkbox of limitedCheckboxes) { - checkbox.enable(); - } - break; case ChatSetupStep.SigningIn: - for (const checkbox of limitedCheckboxes) { - checkbox.disable(); - } buttonLabel = localize('setupChatSignIn', "$(loading~spin) Signing in to {0}...", defaultChat.providerName); break; case ChatSetupStep.Installing: - for (const checkbox of limitedCheckboxes) { - checkbox.disable(); - } buttonLabel = localize('setupChatInstalling', "$(loading~spin) Getting Copilot Ready..."); break; } setVisibility(showLimitedSkuHeader, limitedSkuHeaderContainer); - setVisibility(showLimitedCheckboxes, ...limitedCheckboxContainers); button.label = buttonLabel; button.enabled = this.controller.step === ChatSetupStep.Initial; @@ -926,7 +889,6 @@ class ChatSetupContext extends Disposable { private readonly canSignUpContextKey = ChatContextKeys.Setup.canSignUp.bindTo(this.contextKeyService); private readonly signedOutContextKey = ChatContextKeys.Setup.signedOut.bindTo(this.contextKeyService); - private readonly entitledContextKey = ChatContextKeys.Setup.entitled.bindTo(this.contextKeyService); private readonly limitedContextKey = ChatContextKeys.Setup.limited.bindTo(this.contextKeyService); private readonly triggeredContext = ChatContextKeys.Setup.triggered.bindTo(this.contextKeyService); private readonly installedContext = ChatContextKeys.Setup.installed.bindTo(this.contextKeyService); @@ -1031,7 +993,6 @@ class ChatSetupContext extends Disposable { changed = this.updateContextKey(this.signedOutContextKey, this._state.entitlement === ChatEntitlement.Unknown) || changed; changed = this.updateContextKey(this.canSignUpContextKey, this._state.entitlement === ChatEntitlement.Available) || changed; changed = this.updateContextKey(this.limitedContextKey, this._state.entitlement === ChatEntitlement.Limited) || changed; - changed = this.updateContextKey(this.entitledContextKey, this._state.entitlement === ChatEntitlement.Pro) || changed; changed = this.updateContextKey(this.triggeredContext, !!this._state.triggered) || changed; changed = this.updateContextKey(this.installedContext, !!this._state.installed) || changed; diff --git a/src/vs/workbench/contrib/chat/browser/media/chatViewSetup.css b/src/vs/workbench/contrib/chat/browser/media/chatViewSetup.css index 9fc75ee6c3073..97a06eac5be10 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chatViewSetup.css +++ b/src/vs/workbench/contrib/chat/browser/media/chatViewSetup.css @@ -17,7 +17,7 @@ background-color: var(--vscode-chat-requestBackground); } - .terms-container.is-standalone { + .terms-container { padding-top: 5px; } @@ -29,7 +29,7 @@ } .chat-feature-container .codicon[class*='codicon-'] { - font-size: 20px; + font-size: 16px; } .codicon[class*='codicon-'] { @@ -54,19 +54,4 @@ width: 100%; padding: 4px 7px; } - - /** Checkboxes */ - .checkbox-container { - display: flex; - padding-top: 15px; - } - - .checkbox-label { - flex-basis: fit-content; - cursor: pointer; - } - - .checkbox-label p { - display: inline; - } } diff --git a/src/vs/workbench/contrib/chat/common/chatContextKeys.ts b/src/vs/workbench/contrib/chat/common/chatContextKeys.ts index 8e1f49e7fd3c0..de13af60b8bd7 100644 --- a/src/vs/workbench/contrib/chat/common/chatContextKeys.ts +++ b/src/vs/workbench/contrib/chat/common/chatContextKeys.ts @@ -45,7 +45,6 @@ export namespace ChatContextKeys { canSignUp: new RawContextKey('chatSetupCanSignUp', false, true), // True when user can sign up to be a chat limited user. signedOut: new RawContextKey('chatSetupSignedOut', false, true), // True when user is signed out. - entitled: new RawContextKey('chatSetupEntitled', false, true), // True when user is a chat entitled user. limited: new RawContextKey('chatSetupLimited', false, true), // True when user is a chat limited user. triggered: new RawContextKey('chatSetupTriggered', false, true), // True when chat setup is triggered. diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/multicursor/notebookMulticursor.ts b/src/vs/workbench/contrib/notebook/browser/contrib/multicursor/notebookMulticursor.ts index 2871c2577b18b..c8706e4aeb5a8 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/multicursor/notebookMulticursor.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/multicursor/notebookMulticursor.ts @@ -385,6 +385,18 @@ export class NotebookMultiCursorController extends Disposable implements INotebo } } + private updateViewModelSelections() { + for (const cell of this.trackedCells) { + const controller = this.cursorsControllers.get(cell.cellViewModel.uri); + if (!controller) { + // should not happen + return; + } + + cell.cellViewModel.setSelections(controller.getSelections()); + } + } + private updateFinalUndoRedo() { const anchorCellModel = this.anchorCell?.[1].getModel(); if (!anchorCellModel) { @@ -775,16 +787,10 @@ export class NotebookMultiCursorController extends Disposable implements INotebo if (model) { models.push(model); } - - const controller = this.cursorsControllers.get(cell.cellViewModel.uri); - if (!controller) { - // should not happen - return; - } - controller.setSelections(new ViewModelEventsCollector(), undefined, cell.cellViewModel.getSelections(), CursorChangeReason.Explicit); } await Promise.all(models.map(model => model.undo())); + this.updateViewModelSelections(); this.updateLazyDecorations(); } @@ -795,16 +801,10 @@ export class NotebookMultiCursorController extends Disposable implements INotebo if (model) { models.push(model); } - - const controller = this.cursorsControllers.get(cell.cellViewModel.uri); - if (!controller) { - // should not happen - return; - } - controller.setSelections(new ViewModelEventsCollector(), undefined, cell.cellViewModel.getSelections(), CursorChangeReason.Explicit); } await Promise.all(models.map(model => model.redo())); + this.updateViewModelSelections(); this.updateLazyDecorations(); }