mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
Refactor chat widget welcome view to include additional messages and improve styling (#253720)
* Refactor chat widget welcome view to include additional messages and improve styling * Update experiment configurations to adjust target percentages and group allocations
This commit is contained in:
@@ -11,7 +11,7 @@ import { Codicon } from '../../../../base/common/codicons.js';
|
||||
import { toErrorMessage } from '../../../../base/common/errorMessage.js';
|
||||
import { Emitter, Event } from '../../../../base/common/event.js';
|
||||
import { FuzzyScore } from '../../../../base/common/filters.js';
|
||||
import { MarkdownString } from '../../../../base/common/htmlContent.js';
|
||||
import { IMarkdownString, MarkdownString } from '../../../../base/common/htmlContent.js';
|
||||
import { Iterable } from '../../../../base/common/iterator.js';
|
||||
import { combinedDisposable, Disposable, DisposableStore, IDisposable, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
|
||||
import { ResourceSet } from '../../../../base/common/map.js';
|
||||
@@ -64,7 +64,7 @@ import { ChatEditorOptions } from './chatOptions.js';
|
||||
import './media/chat.css';
|
||||
import './media/chatAgentHover.css';
|
||||
import './media/chatViewWelcome.css';
|
||||
import { ChatViewWelcomePart, IChatSuggestedPrompts, IChatViewWelcomeContent } from './viewsWelcome/chatViewWelcomeController.js';
|
||||
import { ChatViewWelcomePart, IChatViewWelcomeContent } from './viewsWelcome/chatViewWelcomeController.js';
|
||||
import { MicrotaskDelay } from '../../../../base/common/symbols.js';
|
||||
import { IChatRequestVariableEntry, ChatRequestVariableSet as ChatRequestVariableSet, isPromptFileVariableEntry, toPromptFileVariableEntry, PromptFileVariableKind } from '../common/chatVariableEntries.js';
|
||||
import { PromptsConfig } from '../common/promptSyntax/config/config.js';
|
||||
@@ -734,9 +734,6 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||
const numItems = this.viewModel?.getItems().length ?? 0;
|
||||
if (!numItems) {
|
||||
dom.clearNode(this.welcomeMessageContainer);
|
||||
const defaultAgent = this.chatAgentService.getDefaultAgent(this.location, this.input.currentModeKind);
|
||||
const additionalMessage = defaultAgent?.metadata.additionalWelcomeMessage;
|
||||
|
||||
const startupExpValue = startupExpContext.getValue(this.contextKeyService);
|
||||
let welcomeContent: IChatViewWelcomeContent;
|
||||
if (startupExpValue === StartupExperimentGroup.MaximizedChat
|
||||
@@ -746,15 +743,17 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||
this.container.classList.add('experimental-welcome-view');
|
||||
}
|
||||
else {
|
||||
const defaultAgent = this.chatAgentService.getDefaultAgent(this.location, this.input.currentModeKind);
|
||||
const additionalMessage = defaultAgent?.metadata.additionalWelcomeMessage;
|
||||
const tips = this.input.currentModeKind === ChatModeKind.Ask
|
||||
? new MarkdownString(localize('chatWidget.tips', "{0} or type {1} to attach context\n\n{2} to chat with extensions\n\nType {3} to use commands", '$(attach)', '#', '$(mention)', '/'), { supportThemeIcons: true })
|
||||
: new MarkdownString(localize('chatWidget.tips.withoutParticipants', "{0} or type {1} to attach context", '$(attach)', '#'), { supportThemeIcons: true });
|
||||
welcomeContent = this.getWelcomeViewContent();
|
||||
welcomeContent = this.getWelcomeViewContent(additionalMessage);
|
||||
welcomeContent.tips = tips;
|
||||
}
|
||||
this.welcomePart.value = this.instantiationService.createInstance(
|
||||
ChatViewWelcomePart,
|
||||
{ ...welcomeContent, additionalMessage },
|
||||
welcomeContent,
|
||||
{
|
||||
location: this.location,
|
||||
isWidgetAgentWelcomeViewContent: this.input?.currentModeKind === ChatModeKind.Agent
|
||||
@@ -769,58 +768,44 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||
}
|
||||
}
|
||||
|
||||
private getWelcomeViewContent(): IChatViewWelcomeContent {
|
||||
private getWelcomeViewContent(additionalMessage: string | IMarkdownString | undefined): IChatViewWelcomeContent {
|
||||
const baseMessage = localize('chatMessage', "Copilot is powered by AI, so mistakes are possible. Review output carefully before use.");
|
||||
if (this.input.currentModeKind === ChatModeKind.Ask) {
|
||||
return {
|
||||
title: localize('chatDescription', "Ask Copilot"),
|
||||
message: new MarkdownString(baseMessage),
|
||||
icon: Codicon.copilotLarge
|
||||
icon: Codicon.copilotLarge,
|
||||
additionalMessage,
|
||||
};
|
||||
} else if (this.input.currentModeKind === ChatModeKind.Edit) {
|
||||
return {
|
||||
title: localize('editsTitle', "Edit with Copilot"),
|
||||
message: new MarkdownString(localize('editsMessage', "Start your editing session by defining a set of files that you want to work with. Then ask Copilot for the changes you want to make.") + `\n\n${baseMessage}`),
|
||||
icon: Codicon.copilotLarge
|
||||
icon: Codicon.copilotLarge,
|
||||
additionalMessage
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
title: localize('editsTitle', "Edit with Copilot"),
|
||||
message: new MarkdownString(localize('agentMessage', "Ask Copilot to edit your files in [agent mode]({0}). Copilot will automatically use multiple requests to pick files to edit, run terminal commands, and iterate on errors.", 'https://aka.ms/vscode-copilot-agent') + `\n\n${baseMessage}`),
|
||||
icon: Codicon.copilotLarge
|
||||
icon: Codicon.copilotLarge,
|
||||
additionalMessage
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private getExpWelcomeViewContent(): IChatViewWelcomeContent {
|
||||
const baseMessage = localize('chatMessage', "Copilot is powered by AI, so mistakes are possible. Review output carefully before use.");
|
||||
const welcomeContent = {
|
||||
title: localize('expChatTitle', 'Get Started with VS Code'),
|
||||
message: new MarkdownString(baseMessage),
|
||||
const welcomeContent: IChatViewWelcomeContent = {
|
||||
title: localize('expChatTitle', 'Welcome to Copilot'),
|
||||
message: new MarkdownString(localize('expchatMessage', "Let's get started")),
|
||||
icon: Codicon.copilotLarge,
|
||||
suggestedPrompts: this.getExpSuggestedPrompts(),
|
||||
inputPart: this.inputPart.element,
|
||||
additionalMessage: localize('expChatAdditionalMessage', "Review output carefully before use."),
|
||||
isExperimental: true
|
||||
};
|
||||
return welcomeContent;
|
||||
}
|
||||
|
||||
private getExpSuggestedPrompts(): IChatSuggestedPrompts[] {
|
||||
|
||||
return [
|
||||
{
|
||||
icon: Codicon.vscode,
|
||||
label: localize('chatWidget.suggestedPrompts.gettingStarted', "Ask @vscode"),
|
||||
prompt: '@vscode Help me get started with VS Code?',
|
||||
},
|
||||
{
|
||||
icon: Codicon.newFolder,
|
||||
label: localize('chatWidget.suggestedPrompts.newProject', "Create a #new Project"),
|
||||
prompt: '#new Create a new project for me',
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
private async renderChatEditingSessionState() {
|
||||
if (!this.input) {
|
||||
return;
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
|
||||
.interactive-session .experimental-welcome-view & > .chat-welcome-view-input-part {
|
||||
max-width: 650px;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.interactive-session.experimental-welcome-view .chat-input-toolbars > .chat-input-toolbar > div {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Container for ChatViewPane welcome view */
|
||||
@@ -102,44 +107,21 @@ div.chat-welcome-view {
|
||||
}
|
||||
}
|
||||
|
||||
& > .chat-welcome-view-suggested-prompts {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
margin-top: 15px;
|
||||
& > .chat-welcome-experimental-view-message {
|
||||
text-align: center;
|
||||
max-width: 350px;
|
||||
padding: 0 20px 32px;
|
||||
font-size: 16px;
|
||||
|
||||
> .chat-welcome-view-suggested-prompt {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 4px;
|
||||
border-radius: 8px;
|
||||
background-color: var(--vscode-editorWidget-background);
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--vscode-chat-requestBorder, var(--vscode-input-background, transparent));
|
||||
border-radius: 4px;
|
||||
gap: 2px;
|
||||
max-width: 100%;
|
||||
width: fit-content;
|
||||
|
||||
> .chat-welcome-view-suggested-prompt-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 8px;
|
||||
font-size: 4px;
|
||||
color: var(--vscode-icon-foreground) !important;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
> .chat-welcome-view-suggested-prompt-label {
|
||||
font-size: 14px;
|
||||
color: var(--vscode-editorWidget-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
> .chat-welcome-view-suggested-prompt:hover {
|
||||
background-color: var(--vscode-list-hoverBackground);
|
||||
border-color: var(--vscode-focusBorder);
|
||||
a {
|
||||
color: var(--vscode-descriptionForeground);
|
||||
}
|
||||
}
|
||||
|
||||
& > .chat-welcome-view-experimental-additional-message {
|
||||
font-size: 12px;
|
||||
color: var(--vscode-disabledForeground);
|
||||
text-align: center;
|
||||
max-width: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ import { IOpenerService } from '../../../../../platform/opener/common/opener.js'
|
||||
import { defaultButtonStyles } from '../../../../../platform/theme/browser/defaultStyles.js';
|
||||
import { ChatAgentLocation } from '../../common/constants.js';
|
||||
import { chatViewsWelcomeRegistry, IChatViewsWelcomeDescriptor } from './chatViewsWelcome.js';
|
||||
import { IChatWidgetService } from '../chat.js';
|
||||
import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -115,13 +113,7 @@ export interface IChatViewWelcomeContent {
|
||||
additionalMessage?: string | IMarkdownString;
|
||||
tips?: IMarkdownString;
|
||||
inputPart?: HTMLElement;
|
||||
suggestedPrompts?: IChatSuggestedPrompts[];
|
||||
}
|
||||
|
||||
export interface IChatSuggestedPrompts {
|
||||
icon?: ThemeIcon;
|
||||
label: string;
|
||||
prompt: string;
|
||||
isExperimental?: boolean;
|
||||
}
|
||||
|
||||
export interface IChatViewWelcomeRenderOptions {
|
||||
@@ -139,8 +131,6 @@ export class ChatViewWelcomePart extends Disposable {
|
||||
@IOpenerService private openerService: IOpenerService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@ILogService private logService: ILogService,
|
||||
@IChatWidgetService private chatWidgetService: IChatWidgetService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService,
|
||||
) {
|
||||
super();
|
||||
this.element = dom.$('.chat-welcome-view');
|
||||
@@ -165,57 +155,32 @@ export class ChatViewWelcomePart extends Disposable {
|
||||
}
|
||||
|
||||
// Message
|
||||
const message = dom.append(this.element, $('.chat-welcome-view-message'));
|
||||
const message = dom.append(this.element, content.isExperimental ? $('.chat-welcome-experimental-view-message') : $('.chat-welcome-view-message'));
|
||||
if (typeof content.message === 'function') {
|
||||
dom.append(message, content.message(this._register(new DisposableStore())));
|
||||
} else {
|
||||
const messageResult = this.renderMarkdownMessageContent(renderer, content.message, options);
|
||||
dom.append(message, messageResult.element);
|
||||
|
||||
}
|
||||
|
||||
// Additional message
|
||||
if (typeof content.additionalMessage === 'string') {
|
||||
const element = $('');
|
||||
element.textContent = content.additionalMessage;
|
||||
dom.append(message, element);
|
||||
} else if (content.additionalMessage) {
|
||||
const additionalMessageResult = this.renderMarkdownMessageContent(renderer, content.additionalMessage, options);
|
||||
dom.append(message, additionalMessageResult.element);
|
||||
}
|
||||
|
||||
if (content.inputPart) {
|
||||
if (content.isExperimental && content.inputPart) {
|
||||
content.inputPart.querySelector('.chat-attachments-container')?.remove();
|
||||
dom.append(this.element, content.inputPart);
|
||||
}
|
||||
|
||||
if (content.suggestedPrompts && content.suggestedPrompts.length) {
|
||||
|
||||
// create a tile with icon and label for each suggested promot
|
||||
const suggestedPromptsContainer = dom.append(this.element, $('.chat-welcome-view-suggested-prompts'));
|
||||
for (const prompt of content.suggestedPrompts) {
|
||||
const promptElement = dom.append(suggestedPromptsContainer, $('.chat-welcome-view-suggested-prompt'));
|
||||
if (prompt.icon) {
|
||||
const iconElement = dom.append(promptElement, $('.chat-welcome-view-suggested-prompt-icon'));
|
||||
iconElement.appendChild(renderIcon(prompt.icon));
|
||||
}
|
||||
const labelElement = dom.append(promptElement, $('.chat-welcome-view-suggested-prompt-label'));
|
||||
labelElement.textContent = prompt.label;
|
||||
this._register(dom.addDisposableListener(promptElement, dom.EventType.CLICK, () => {
|
||||
|
||||
type SuggestedPromptClickEvent = { suggestedPrompt: string };
|
||||
|
||||
type SuggestedPromptClickData = {
|
||||
owner: 'bhavyaus';
|
||||
comment: 'Event used to gain insights into when suggested prompts are clicked.';
|
||||
suggestedPrompt: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The suggested prompt clicked.' };
|
||||
};
|
||||
|
||||
this.telemetryService.publicLog2<SuggestedPromptClickEvent, SuggestedPromptClickData>('chat.clickedSuggestedPrompt', {
|
||||
suggestedPrompt: prompt.prompt,
|
||||
});
|
||||
|
||||
this.chatWidgetService.lastFocusedWidget?.setInput(prompt.prompt);
|
||||
}));
|
||||
if (typeof content.additionalMessage === 'string') {
|
||||
const additionalMsg = $('.chat-welcome-view-experimental-additional-message');
|
||||
additionalMsg.textContent = content.additionalMessage;
|
||||
dom.append(this.element, additionalMsg);
|
||||
}
|
||||
// also append telemetry message if available
|
||||
} else {
|
||||
// Additional message
|
||||
if (typeof content.additionalMessage === 'string') {
|
||||
const element = $('');
|
||||
element.textContent = content.additionalMessage;
|
||||
dom.append(message, element);
|
||||
} else if (content.additionalMessage) {
|
||||
const additionalMessageResult = this.renderMarkdownMessageContent(renderer, content.additionalMessage, options);
|
||||
dom.append(message, additionalMessageResult.element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user