Skip to content

Commit c514ae6

Browse files
authored
chat - drop special centered layout for out of the box (microsoft#273054)
* chat - drop special centered layout for out of the box * fix condition for terms * restore suggested actions
1 parent d6720d0 commit c514ae6

File tree

2 files changed

+46
-160
lines changed

2 files changed

+46
-160
lines changed

src/vs/workbench/contrib/chat/browser/chatWidget.ts

Lines changed: 46 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import './media/chat.css';
7+
import './media/chatAgentHover.css';
8+
import './media/chatViewWelcome.css';
69
import * as dom from '../../../../base/browser/dom.js';
710
import { IMouseWheelEvent } from '../../../../base/browser/mouseEvent.js';
811
import { Button } from '../../../../base/browser/ui/button/button.js';
@@ -50,11 +53,10 @@ import { ITelemetryService } from '../../../../platform/telemetry/common/telemet
5053
import { buttonSecondaryBackground, buttonSecondaryForeground, buttonSecondaryHoverBackground } from '../../../../platform/theme/common/colorRegistry.js';
5154
import { asCssVariable } from '../../../../platform/theme/common/colorUtils.js';
5255
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
53-
import { IWorkspaceContextService, WorkbenchState } from '../../../../platform/workspace/common/workspace.js';
5456
import { EditorResourceAccessor } from '../../../../workbench/common/editor.js';
5557
import { IEditorService } from '../../../../workbench/services/editor/common/editorService.js';
5658
import { ViewContainerLocation } from '../../../common/views.js';
57-
import { ChatEntitlement, IChatEntitlementService } from '../../../services/chat/common/chatEntitlementService.js';
59+
import { IChatEntitlementService } from '../../../services/chat/common/chatEntitlementService.js';
5860
import { IWorkbenchLayoutService, Position } from '../../../services/layout/browser/layoutService.js';
5961
import { IViewsService } from '../../../services/views/common/viewsService.js';
6062
import { checkModeOption } from '../common/chat.js';
@@ -90,10 +92,8 @@ import { ChatInputPart, IChatInputPartOptions, IChatInputStyles } from './chatIn
9092
import { ChatListDelegate, ChatListItemRenderer, IChatListItemTemplate, IChatRendererDelegate } from './chatListRenderer.js';
9193
import { ChatEditorOptions } from './chatOptions.js';
9294
import { ChatViewPane } from './chatViewPane.js';
93-
import './media/chat.css';
94-
import './media/chatAgentHover.css';
95-
import './media/chatViewWelcome.css';
9695
import { ChatViewWelcomePart, IChatSuggestedPrompts, IChatViewWelcomeContent } from './viewsWelcome/chatViewWelcomeController.js';
96+
import { IWorkspaceContextService, WorkbenchState } from '../../../../platform/workspace/common/workspace.js';
9797

9898
const $ = dom.$;
9999

@@ -379,7 +379,6 @@ export class ChatWidget extends Disposable implements IChatWidget {
379379
private readonly _lockedToCodingAgentContextKey: IContextKey<boolean>;
380380
private readonly _agentSupportsAttachmentsContextKey: IContextKey<boolean>;
381381
private _attachmentCapabilities: IChatAgentAttachmentCapabilities = supportsAllAttachments;
382-
private lastWelcomeViewChatMode: ChatModeKind | undefined;
383382

384383
// Cache for prompt file descriptions to avoid async calls during rendering
385384
private readonly promptDescriptionsCache = new Map<string, string>();
@@ -455,12 +454,6 @@ export class ChatWidget extends Disposable implements IChatWidget {
455454

456455
readonly viewContext: IChatWidgetViewContext;
457456

458-
private shouldShowChatSetup(): boolean {
459-
// Check if chat is not installed OR user can sign up for free
460-
// Equivalent to: ChatContextKeys.Setup.installed.negate() OR ChatContextKeys.Entitlement.canSignUp
461-
return !this.chatEntitlementService.sentiment.installed || this.chatEntitlementService.entitlement === ChatEntitlement.Available;
462-
}
463-
464457
get supportsChangingModes(): boolean {
465458
return !!this.viewOptions.supportsChangingModes;
466459
}
@@ -495,14 +488,14 @@ export class ChatWidget extends Disposable implements IChatWidget {
495488
@ITelemetryService private readonly telemetryService: ITelemetryService,
496489
@IPromptsService private readonly promptsService: IPromptsService,
497490
@ILanguageModelToolsService private readonly toolsService: ILanguageModelToolsService,
498-
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
499491
@IChatModeService private readonly chatModeService: IChatModeService,
500492
@IChatLayoutService private readonly chatLayoutService: IChatLayoutService,
501493
@IChatEntitlementService private readonly chatEntitlementService: IChatEntitlementService,
502494
@ICommandService private readonly commandService: ICommandService,
503495
@IHoverService private readonly hoverService: IHoverService,
504496
@IChatSessionsService private readonly chatSessionsService: IChatSessionsService,
505-
@IChatTodoListService private readonly chatTodoListService: IChatTodoListService
497+
@IChatTodoListService private readonly chatTodoListService: IChatTodoListService,
498+
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
506499
) {
507500
super();
508501
this._lockedToCodingAgentContextKey = ChatContextKeys.lockedToCodingAgent.bindTo(this.contextKeyService);
@@ -692,35 +685,13 @@ export class ChatWidget extends Disposable implements IChatWidget {
692685

693686
this._register(this.onDidChangeParsedInput(() => this.updateChatInputContext()));
694687

695-
// Listen to entitlement and sentiment changes instead of context keys
696-
this._register(this.chatEntitlementService.onDidChangeEntitlement(() => {
697-
if (!this.shouldShowChatSetup()) {
698-
this.resetWelcomeViewInput();
699-
}
700-
}));
701-
this._register(this.chatEntitlementService.onDidChangeSentiment(() => {
702-
if (!this.shouldShowChatSetup()) {
703-
this.resetWelcomeViewInput();
704-
}
705-
}));
706688
this._register(this.chatTodoListService.onDidUpdateTodos((sessionId) => {
707689
if (this.viewModel?.sessionId === sessionId) {
708690
this.inputPart.renderChatTodoListWidget(sessionId);
709691
}
710692
}));
711693
}
712694

713-
private resetWelcomeViewInput(): void {
714-
// reset the input in welcome view if it was rendered in experimental mode
715-
if (this.container.classList.contains('new-welcome-view')) {
716-
this.container.classList.remove('new-welcome-view');
717-
const renderFollowups = this.viewOptions.renderFollowups ?? false;
718-
const renderStyle = this.viewOptions.renderStyle;
719-
this.createInput(this.container, { renderFollowups, renderStyle });
720-
this.input.setChatMode(this.lastWelcomeViewChatMode ?? ChatModeKind.Agent);
721-
}
722-
}
723-
724695
private _lastSelectedAgent: IChatAgentData | undefined;
725696
set lastSelectedAgent(agent: IChatAgentData | undefined) {
726697
this.parsedChatRequest = undefined;
@@ -1004,13 +975,6 @@ export class ChatWidget extends Disposable implements IChatWidget {
1004975
});
1005976

1006977

1007-
// reset the input in welcome view if it was rendered in experimental mode
1008-
if (this.viewModel?.getItems().length) {
1009-
this.resetWelcomeViewInput();
1010-
// TODO@bhavyaus
1011-
// this.focusInput();
1012-
}
1013-
1014978
if (treeItems.length > 0) {
1015979
this.updateChatViewVisibility();
1016980
} else {
@@ -1089,14 +1053,16 @@ export class ChatWidget extends Disposable implements IChatWidget {
10891053

10901054
let welcomeContent: IChatViewWelcomeContent;
10911055
const defaultAgent = this.chatAgentService.getDefaultAgent(this.location, this.input.currentModeKind);
1092-
let additionalMessage = defaultAgent?.metadata.additionalWelcomeMessage;
1056+
let additionalMessage: string | IMarkdownString | undefined;
1057+
if (this.chatEntitlementService.anonymous && !this.chatEntitlementService.sentiment.installed) {
1058+
additionalMessage = new MarkdownString(localize({ key: 'settings', comment: ['{Locked="]({2})"}', '{Locked="]({3})"}'] }, "By continuing with {0} Copilot, you agree to {1}'s [Terms]({2}) and [Privacy Statement]({3}).", defaultChat.provider.default.name, defaultChat.provider.default.name, defaultChat.termsStatementUrl, defaultChat.privacyStatementUrl), { isTrusted: true });
1059+
} else {
1060+
additionalMessage = defaultAgent?.metadata.additionalWelcomeMessage;
1061+
}
10931062
if (!additionalMessage && !this._lockedAgent) {
10941063
additionalMessage = this._getGenerateInstructionsMessage();
10951064
}
1096-
if (this.shouldShowChatSetup()) {
1097-
welcomeContent = this.getNewWelcomeViewContent();
1098-
this.container.classList.add('new-welcome-view');
1099-
} else if (expEmptyState) {
1065+
if (expEmptyState) {
11001066
welcomeContent = this.getWelcomeViewContent(additionalMessage, expEmptyState);
11011067
} else {
11021068
const defaultTips = this.input.currentModeKind === ChatModeKind.Ask
@@ -1440,71 +1406,40 @@ export class ChatWidget extends Disposable implements IChatWidget {
14401406
}
14411407
}
14421408

1443-
private getNewWelcomeViewContent(): IChatViewWelcomeContent {
1444-
let additionalMessage: string | IMarkdownString | undefined = undefined;
1445-
if (this.chatEntitlementService.anonymous) {
1446-
additionalMessage = new MarkdownString(localize({ key: 'settings', comment: ['{Locked="]({2})"}', '{Locked="]({3})"}'] }, "AI responses may be inaccurate.\nBy continuing with {0} Copilot, you agree to {1}'s [Terms]({2}) and [Privacy Statement]({3}).", defaultChat.provider.default.name, defaultChat.provider.default.name, defaultChat.termsStatementUrl, defaultChat.privacyStatementUrl), { isTrusted: true });
1447-
} else {
1448-
additionalMessage = localize('expChatAdditionalMessage', "AI responses may be inaccurate.");
1449-
}
1450-
1451-
// Check for provider-specific customizations
1452-
const providerIcon = this._lockedAgent?.id ? this.chatSessionsService.getIconForSessionType(this._lockedAgent.id) : undefined;
1453-
const providerTitle = this._lockedAgent ? this.chatSessionsService.getWelcomeTitleForSessionType(this._lockedAgent.id) : undefined;
1454-
const providerMessage = this._lockedAgent ? this.chatSessionsService.getWelcomeMessageForSessionType(this._lockedAgent.id) : undefined;
1455-
const providerTips = this._lockedAgent ? this.chatSessionsService.getWelcomeTipsForSessionType(this._lockedAgent.id) : undefined;
1456-
const suggestedPrompts = this._lockedAgent ? undefined : this.getNewSuggestedPrompts();
1457-
const welcomeContent: IChatViewWelcomeContent = {
1458-
title: providerTitle ?? localize('expChatTitle', 'Build with agents'),
1459-
message: providerMessage ? new MarkdownString(providerMessage) : new MarkdownString(localize('expchatMessage', "Let's get started")),
1460-
icon: providerIcon ?? Codicon.chatSparkle,
1461-
inputPart: this.inputPart.element,
1462-
additionalMessage,
1463-
isNew: true,
1464-
suggestedPrompts,
1465-
useLargeIcon: !!providerIcon,
1466-
};
1467-
1468-
// Add contributed tips if available
1469-
if (providerTips) {
1470-
welcomeContent.tips = new MarkdownString(providerTips, { supportThemeIcons: true });
1471-
}
1472-
return welcomeContent;
1473-
}
1409+
private getPromptFileSuggestions(): IChatSuggestedPrompts[] {
14741410

1475-
private getNewSuggestedPrompts(): IChatSuggestedPrompts[] {
1476-
// Check if the workbench is empty
1477-
const isEmpty = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
1478-
if (isEmpty) {
1479-
return [
1480-
{
1481-
icon: Codicon.vscode,
1482-
label: localize('chatWidget.suggestedPrompts.gettingStarted', "Ask @vscode"),
1483-
prompt: localize('chatWidget.suggestedPrompts.gettingStartedPrompt', "@vscode How do I change the theme to light mode?"),
1484-
},
1485-
{
1486-
icon: Codicon.newFolder,
1487-
label: localize('chatWidget.suggestedPrompts.newProject', "Create Project"),
1488-
prompt: localize('chatWidget.suggestedPrompts.newProjectPrompt', "Create a #new Hello World project in TypeScript"),
1489-
}
1490-
];
1491-
} else {
1492-
return [
1493-
{
1494-
icon: Codicon.debugAlt,
1495-
label: localize('chatWidget.suggestedPrompts.buildWorkspace', "Build Workspace"),
1496-
prompt: localize('chatWidget.suggestedPrompts.buildWorkspacePrompt', "How do I build this workspace?"),
1497-
},
1498-
{
1499-
icon: Codicon.gear,
1500-
label: localize('chatWidget.suggestedPrompts.findConfig', "Show Config"),
1501-
prompt: localize('chatWidget.suggestedPrompts.findConfigPrompt', "Where is the configuration for this project defined?"),
1502-
}
1503-
];
1411+
// Use predefined suggestions for new users
1412+
if (!this.chatEntitlementService.sentiment.installed) {
1413+
const isEmpty = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
1414+
if (isEmpty) {
1415+
return [
1416+
{
1417+
icon: Codicon.vscode,
1418+
label: localize('chatWidget.suggestedPrompts.gettingStarted', "Ask @vscode"),
1419+
prompt: localize('chatWidget.suggestedPrompts.gettingStartedPrompt', "@vscode How do I change the theme to light mode?"),
1420+
},
1421+
{
1422+
icon: Codicon.newFolder,
1423+
label: localize('chatWidget.suggestedPrompts.newProject', "Create Project"),
1424+
prompt: localize('chatWidget.suggestedPrompts.newProjectPrompt', "Create a #new Hello World project in TypeScript"),
1425+
}
1426+
];
1427+
} else {
1428+
return [
1429+
{
1430+
icon: Codicon.debugAlt,
1431+
label: localize('chatWidget.suggestedPrompts.buildWorkspace', "Build Workspace"),
1432+
prompt: localize('chatWidget.suggestedPrompts.buildWorkspacePrompt', "How do I build this workspace?"),
1433+
},
1434+
{
1435+
icon: Codicon.gear,
1436+
label: localize('chatWidget.suggestedPrompts.findConfig', "Show Config"),
1437+
prompt: localize('chatWidget.suggestedPrompts.findConfigPrompt', "Where is the configuration for this project defined?"),
1438+
}
1439+
];
1440+
}
15041441
}
1505-
}
15061442

1507-
private getPromptFileSuggestions(): IChatSuggestedPrompts[] {
15081443
// Get the current workspace folder context if available
15091444
const activeEditor = this.editorService.activeEditor;
15101445
const resource = activeEditor ? EditorResourceAccessor.getOriginalUri(activeEditor) : undefined;
@@ -2268,7 +2203,6 @@ export class ChatWidget extends Disposable implements IChatWidget {
22682203
this._welcomeRenderScheduler.schedule();
22692204
}));
22702205
this._register(this.input.onDidChangeCurrentChatMode(() => {
2271-
this.lastWelcomeViewChatMode = this.input.currentModeKind;
22722206
this._welcomeRenderScheduler.schedule();
22732207
this.refreshParsedInput();
22742208
this.renderFollowups();
@@ -2757,11 +2691,7 @@ export class ChatWidget extends Disposable implements IChatWidget {
27572691
this.inlineInputPart?.layout(layoutHeight, width);
27582692
}
27592693

2760-
if (this.container.classList.contains('new-welcome-view')) {
2761-
this.inputPart.layout(layoutHeight, Math.min(width, 650));
2762-
} else {
2763-
this.inputPart.layout(layoutHeight, width);
2764-
}
2694+
this.inputPart.layout(layoutHeight, width);
27652695

27662696
const inputHeight = this.inputPart.inputPartHeight;
27672697
const chatSuggestNextWidgetHeight = this.chatSuggestNextWidget.height;

src/vs/workbench/contrib/chat/browser/media/chatViewWelcome.css

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,6 @@
2121
flex-direction: column;
2222
height: 100%;
2323

24-
&.new-welcome-view {
25-
.interactive-input-part {
26-
.dropdown-action-container {
27-
display: none;
28-
}
29-
30-
.chat-attachments-container {
31-
display: none;
32-
}
33-
}
34-
35-
.chat-input-toolbars > .chat-input-toolbar > div {
36-
display: none;
37-
}
38-
39-
.chat-input-toolbars .action-item:not(:has(.monaco-dropdown-with-primary)) {
40-
display: none;
41-
}
42-
}
43-
4424
/* chat welcome container */
4525
.chat-welcome-view-container {
4626
display: flex;
@@ -65,12 +45,6 @@
6545
}
6646
}
6747
}
68-
69-
.new-welcome-view & > .chat-welcome-view-input-part {
70-
max-width: 650px;
71-
margin-bottom: 8px;
72-
/* Reduced margin to make room for prompts below */
73-
}
7448
}
7549

7650
/* Container for ChatViewPane welcome view */
@@ -291,24 +265,6 @@ div.chat-welcome-view {
291265
}
292266
}
293267

294-
/* Fresh login view - move prompts below input box instead of at bottom */
295-
.new-welcome-view .chat-welcome-view-suggested-prompts {
296-
position: relative;
297-
bottom: auto;
298-
left: auto;
299-
right: auto;
300-
margin-top: 8px;
301-
margin-bottom: 48px;
302-
justify-content: center;
303-
padding: 0 12px;
304-
}
305-
306-
/* Hide the title for fresh login view */
307-
.new-welcome-view .chat-welcome-view-suggested-prompts .chat-welcome-view-suggested-prompts-title {
308-
display: none;
309-
}
310-
311-
312268
.chat-welcome-history-root {
313269
width: 100%;
314270
padding: 8px;

0 commit comments

Comments
 (0)