mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-28 06:31:58 +00:00
This commit is contained in:
parent
f69c21c5ff
commit
302c914060
3
.github/CODENOTIFY
vendored
3
.github/CODENOTIFY
vendored
@ -104,6 +104,9 @@ src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @roblourens
|
||||
src/vs/workbench/contrib/chat/browser/chatSetup/** @bpasero
|
||||
src/vs/workbench/contrib/chat/browser/chatStatus/** @bpasero
|
||||
src/vs/workbench/contrib/chat/browser/chatViewPane.ts @bpasero
|
||||
src/vs/workbench/contrib/chat/browser/media/chatViewPane.css @bpasero
|
||||
src/vs/workbench/contrib/chat/browser/chatViewTitleControl.ts @bpasero
|
||||
src/vs/workbench/contrib/chat/browser/media/chatViewTitleControl.css @bpasero
|
||||
src/vs/workbench/contrib/chat/browser/chatManagement/chatUsageWidget.ts @bpasero
|
||||
src/vs/workbench/contrib/chat/browser/chatManagement/media/chatUsageWidget.css @bpasero
|
||||
src/vs/workbench/contrib/chat/browser/agentSessions/** @bpasero
|
||||
|
||||
@ -281,6 +281,7 @@ export class MenuId {
|
||||
static readonly ChatSessionsMenu = new MenuId('ChatSessionsMenu');
|
||||
static readonly ChatSessionsCreateSubMenu = new MenuId('ChatSessionsCreateSubMenu');
|
||||
static readonly ChatRecentSessionsToolbar = new MenuId('ChatRecentSessionsToolbar');
|
||||
static readonly ChatViewSessionTitleToolbar = new MenuId('ChatViewSessionTitleToolbar');
|
||||
static readonly ChatConfirmationMenu = new MenuId('ChatConfirmationMenu');
|
||||
static readonly ChatEditorInlineExecute = new MenuId('ChatEditorInputExecute');
|
||||
static readonly ChatEditorInlineInputSide = new MenuId('ChatEditorInputSide');
|
||||
|
||||
@ -1836,8 +1836,6 @@ registerAction2(class ToggleChatViewRecentSessionsAction extends Action2 {
|
||||
super({
|
||||
id: 'workbench.action.chat.toggleChatViewRecentSessions',
|
||||
title: localize2('chat.toggleChatViewRecentSessions.label', "Show Recent Sessions"),
|
||||
category: CHAT_CATEGORY,
|
||||
precondition: ChatContextKeys.enabled,
|
||||
toggled: ContextKeyExpr.equals(`config.${ChatConfiguration.ChatViewRecentSessionsEnabled}`, true),
|
||||
menu: {
|
||||
id: MenuId.ChatWelcomeContext,
|
||||
@ -1855,3 +1853,26 @@ registerAction2(class ToggleChatViewRecentSessionsAction extends Action2 {
|
||||
await configurationService.updateValue(ChatConfiguration.ChatViewRecentSessionsEnabled, !chatViewRecentSessionsEnabled);
|
||||
}
|
||||
});
|
||||
|
||||
registerAction2(class ToggleChatViewTitleAction extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'workbench.action.chat.toggleChatViewTitle',
|
||||
title: localize2('chat.toggleChatViewTitle.label', "Show Chat Title"),
|
||||
toggled: ContextKeyExpr.equals(`config.${ChatConfiguration.ChatViewTitleEnabled}`, true),
|
||||
menu: {
|
||||
id: MenuId.ChatWelcomeContext,
|
||||
group: '1_modify',
|
||||
order: 2,
|
||||
when: ChatContextKeys.inChatEditor.negate()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
|
||||
const chatViewTitleEnabled = configurationService.getValue<boolean>(ChatConfiguration.ChatViewTitleEnabled);
|
||||
await configurationService.updateValue(ChatConfiguration.ChatViewTitleEnabled, !chatViewTitleEnabled);
|
||||
}
|
||||
});
|
||||
|
||||
@ -160,6 +160,15 @@ export function registerNewChatActions() {
|
||||
});
|
||||
CommandsRegistry.registerCommandAlias(ACTION_ID_NEW_EDIT_SESSION, ACTION_ID_NEW_CHAT);
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.ChatViewSessionTitleToolbar, {
|
||||
command: {
|
||||
id: ACTION_ID_NEW_CHAT,
|
||||
title: localize2('chat.goBack', "Go Back"),
|
||||
icon: Codicon.arrowLeft,
|
||||
},
|
||||
group: 'navigation'
|
||||
});
|
||||
|
||||
registerAction2(class UndoChatEditInteractionAction extends EditingSessionAction {
|
||||
constructor() {
|
||||
super({
|
||||
|
||||
@ -373,6 +373,15 @@ configurationRegistry.registerConfiguration({
|
||||
mode: 'auto'
|
||||
}
|
||||
},
|
||||
[ChatConfiguration.ChatViewTitleEnabled]: { // TODO@bpasero decide on a default
|
||||
type: 'boolean',
|
||||
default: product.quality !== 'stable',
|
||||
description: nls.localize('chat.viewTitle.enabled', "Show the title of the chat above the chat in the chat view."),
|
||||
tags: ['preview', 'experimental'],
|
||||
experiment: {
|
||||
mode: 'auto'
|
||||
}
|
||||
},
|
||||
[ChatConfiguration.NotifyWindowOnResponseReceived]: {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
|
||||
@ -64,7 +64,7 @@ const chatViewDescriptor: IViewDescriptor = {
|
||||
},
|
||||
order: 1
|
||||
},
|
||||
ctorDescriptor: new SyncDescriptor(ChatViewPane, [{ location: ChatAgentLocation.Chat }]),
|
||||
ctorDescriptor: new SyncDescriptor(ChatViewPane),
|
||||
when: ContextKeyExpr.or(
|
||||
ContextKeyExpr.or(
|
||||
ChatContextKeys.Setup.hidden,
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import './media/chatViewPane.css';
|
||||
import { $, addDisposableListener, append, EventHelper, EventType, getWindow, setVisibility } from '../../../../base/browser/dom.js';
|
||||
import { StandardMouseEvent } from '../../../../base/browser/mouseEvent.js';
|
||||
import { CancellationToken } from '../../../../base/common/cancellation.js';
|
||||
@ -46,7 +47,7 @@ import { showCloseActiveChatNotification } from './actions/chatCloseNotification
|
||||
import { AgentSessionsControl } from './agentSessions/agentSessionsControl.js';
|
||||
import { AgentSessionsListDelegate } from './agentSessions/agentSessionsViewer.js';
|
||||
import { ChatWidget } from './chatWidget.js';
|
||||
import './media/chatViewPane.css';
|
||||
import { ChatViewTitleControl } from './chatViewTitleControl.js';
|
||||
import { ChatViewWelcomeController, IViewWelcomeDelegate } from './viewsWelcome/chatViewWelcomeController.js';
|
||||
|
||||
interface IChatViewPaneState extends Partial<IChatModelInputState> {
|
||||
@ -65,8 +66,6 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
private _widget!: ChatWidget;
|
||||
get widget(): ChatWidget { return this._widget; }
|
||||
|
||||
private readonly modelRef = this._register(new MutableDisposable<IChatModelReference>());
|
||||
|
||||
private readonly memento: Memento<IChatViewPaneState>;
|
||||
private readonly viewState: IChatViewPaneState;
|
||||
|
||||
@ -77,14 +76,16 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
private sessionsControl: AgentSessionsControl | undefined;
|
||||
private sessionsCount: number = 0;
|
||||
|
||||
private welcomeController: ChatViewWelcomeController | undefined;
|
||||
private titleControl: ChatViewTitleControl | undefined;
|
||||
|
||||
private restoringSession: Promise<void> | undefined;
|
||||
private welcomeController: ChatViewWelcomeController | undefined;
|
||||
|
||||
private lastDimensions: { height: number; width: number } | undefined;
|
||||
|
||||
private restoringSession: Promise<void> | undefined;
|
||||
private readonly modelRef = this._register(new MutableDisposable<IChatModelReference>());
|
||||
|
||||
constructor(
|
||||
private readonly chatOptions: { location: ChatAgentLocation.Chat },
|
||||
options: IViewPaneOptions,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@ -125,7 +126,7 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
|
||||
private registerListeners(): void {
|
||||
this._register(this.chatAgentService.onDidChangeAgents(() => {
|
||||
if (this.chatAgentService.getDefaultAgent(this.chatOptions?.location)) {
|
||||
if (this.chatAgentService.getDefaultAgent(ChatAgentLocation.Chat)) {
|
||||
if (!this._widget?.viewModel && !this.restoringSession) {
|
||||
const info = this.getTransferredOrPersistedSessionInfo();
|
||||
this.restoringSession =
|
||||
@ -144,11 +145,13 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
if (info.inputState && modelRef) {
|
||||
modelRef.object.inputModel.setState(info.inputState);
|
||||
}
|
||||
await this.updateModel(modelRef);
|
||||
|
||||
await this.showModel(modelRef);
|
||||
} finally {
|
||||
this._widget.setVisible(wasVisible);
|
||||
}
|
||||
});
|
||||
|
||||
this.restoringSession.finally(() => this.restoringSession = undefined);
|
||||
}
|
||||
}
|
||||
@ -158,7 +161,7 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
}
|
||||
|
||||
private getTransferredOrPersistedSessionInfo(): { sessionId?: string; inputState?: IChatModelInputState; mode?: ChatModeKind } {
|
||||
if (this.chatService.transferredSessionData?.location === this.chatOptions.location) {
|
||||
if (this.chatService.transferredSessionData?.location === ChatAgentLocation.Chat) {
|
||||
const sessionId = this.chatService.transferredSessionData.sessionId;
|
||||
return {
|
||||
sessionId,
|
||||
@ -176,7 +179,7 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
} : undefined;
|
||||
}
|
||||
|
||||
private async updateModel(modelRef?: IChatModelReference | undefined) {
|
||||
private async showModel(modelRef?: IChatModelReference | undefined): Promise<IChatModel | undefined> {
|
||||
|
||||
// Check if we're disposing a model with an active request
|
||||
if (this.modelRef.value?.object.requestInProgress.get()) {
|
||||
@ -186,20 +189,24 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
|
||||
this.modelRef.value = undefined;
|
||||
|
||||
const ref = modelRef ?? (this.chatService.transferredSessionData?.sessionId && this.chatService.transferredSessionData?.location === this.chatOptions.location
|
||||
const ref = modelRef ?? (this.chatService.transferredSessionData?.sessionId && this.chatService.transferredSessionData?.location === ChatAgentLocation.Chat
|
||||
? await this.chatService.getOrRestoreSession(LocalChatSessionUri.forSession(this.chatService.transferredSessionData.sessionId))
|
||||
: this.chatService.startSession(this.chatOptions.location));
|
||||
: this.chatService.startSession(ChatAgentLocation.Chat));
|
||||
if (!ref) {
|
||||
throw new Error('Could not start chat session');
|
||||
}
|
||||
this.modelRef.value = ref;
|
||||
const model = ref.object;
|
||||
|
||||
// Update widget lock state based on session type
|
||||
await this.updateWidgetLockState(model.sessionResource);
|
||||
|
||||
this.viewState.sessionId = model.sessionId;
|
||||
this.viewState.sessionId = model.sessionId; // remember as model to restore in view state
|
||||
this._widget.setModel(model);
|
||||
|
||||
// Update title control
|
||||
this.titleControl?.update(model);
|
||||
|
||||
// Update the toolbar context with new sessionId
|
||||
this.updateActions();
|
||||
|
||||
@ -208,11 +215,11 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
|
||||
override shouldShowWelcome(): boolean {
|
||||
const noPersistedSessions = !this.chatService.hasSessions();
|
||||
const hasCoreAgent = this.chatAgentService.getAgents().some(agent => agent.isCore && agent.locations.includes(this.chatOptions.location));
|
||||
const hasDefaultAgent = this.chatAgentService.getDefaultAgent(this.chatOptions.location) !== undefined; // only false when Hide AI Features has run and unregistered the setup agents
|
||||
const hasCoreAgent = this.chatAgentService.getAgents().some(agent => agent.isCore && agent.locations.includes(ChatAgentLocation.Chat));
|
||||
const hasDefaultAgent = this.chatAgentService.getDefaultAgent(ChatAgentLocation.Chat) !== undefined; // only false when Hide AI Features has run and unregistered the setup agents
|
||||
const shouldShow = !hasCoreAgent && (!hasDefaultAgent || !this._widget?.viewModel && noPersistedSessions);
|
||||
|
||||
this.logService.trace(`ChatViewPane#shouldShowWelcome(${this.chatOptions.location}) = ${shouldShow}: hasCoreAgent=${hasCoreAgent} hasDefaultAgent=${hasDefaultAgent} || noViewModel=${!this._widget?.viewModel} && noPersistedSessions=${noPersistedSessions}`);
|
||||
this.logService.trace(`ChatViewPane#shouldShowWelcome() = ${shouldShow}: hasCoreAgent=${hasCoreAgent} hasDefaultAgent=${hasDefaultAgent} || noViewModel=${!this._widget?.viewModel} && noPersistedSessions=${noPersistedSessions}`);
|
||||
|
||||
return !!shouldShow;
|
||||
}
|
||||
@ -226,6 +233,7 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
this.viewPaneContainer.classList.add('chat-viewpane');
|
||||
|
||||
this.createControls(parent);
|
||||
|
||||
this.setupContextMenu(parent);
|
||||
|
||||
this.applyModel();
|
||||
@ -236,8 +244,11 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
// Sessions Control
|
||||
this.createSessionsControl(parent);
|
||||
|
||||
// Title Control
|
||||
this.createTitleControl(parent);
|
||||
|
||||
// Welcome Control
|
||||
this.welcomeController = this._register(this.instantiationService.createInstance(ChatViewWelcomeController, parent, this, this.chatOptions.location));
|
||||
this.welcomeController = this._register(this.instantiationService.createInstance(ChatViewWelcomeController, parent, this, ChatAgentLocation.Chat));
|
||||
|
||||
// Chat Widget
|
||||
this.createChatWidget(parent);
|
||||
@ -314,9 +325,9 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
|
||||
const newSessionsContainerVisible =
|
||||
this.configurationService.getValue<boolean>(ChatConfiguration.ChatViewRecentSessionsEnabled) && // enabled in settings
|
||||
(!this._widget || this._widget?.isEmpty()) && // chat widget empty
|
||||
!this.welcomeController?.isShowingWelcome.get() && // welcome not showing
|
||||
this.sessionsCount > 0; // has sessions
|
||||
(!this._widget || this._widget?.isEmpty()) && // chat widget empty
|
||||
!this.welcomeController?.isShowingWelcome.get() && // welcome not showing
|
||||
this.sessionsCount > 0; // has sessions
|
||||
|
||||
this.viewPaneContainer.classList.toggle('has-sessions-control', newSessionsContainerVisible);
|
||||
|
||||
@ -329,6 +340,21 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
};
|
||||
}
|
||||
|
||||
private createTitleControl(parent: HTMLElement): void {
|
||||
this.titleControl = this._register(this.instantiationService.createInstance(ChatViewTitleControl,
|
||||
parent,
|
||||
{
|
||||
updateTitle: title => this.updateTitle(title)
|
||||
}
|
||||
));
|
||||
|
||||
this._register(this.titleControl.onDidChangeHeight(() => {
|
||||
if (this.lastDimensions) {
|
||||
this.layoutBody(this.lastDimensions.height, this.lastDimensions.width);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private createChatWidget(parent: HTMLElement): void {
|
||||
const locationBasedColors = this.getLocationBasedColors();
|
||||
|
||||
@ -338,11 +364,11 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
const scopedInstantiationService = this._register(this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService])));
|
||||
this._widget = this._register(scopedInstantiationService.createInstance(
|
||||
ChatWidget,
|
||||
this.chatOptions.location,
|
||||
ChatAgentLocation.Chat,
|
||||
{ viewId: this.id },
|
||||
{
|
||||
autoScroll: mode => mode !== ChatModeKind.Ask,
|
||||
renderFollowups: this.chatOptions.location === ChatAgentLocation.Chat,
|
||||
renderFollowups: true,
|
||||
supportsFileReferences: true,
|
||||
clear: () => this.clear(),
|
||||
rendererOptions: {
|
||||
@ -353,7 +379,7 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
progressMessageAtBottomOfResponse: mode => mode !== ChatModeKind.Ask,
|
||||
},
|
||||
editorOverflowWidgetsDomNode,
|
||||
enableImplicitContext: this.chatOptions.location === ChatAgentLocation.Chat,
|
||||
enableImplicitContext: true,
|
||||
enableWorkingSet: 'explicit',
|
||||
supportsChangingModes: true,
|
||||
},
|
||||
@ -390,28 +416,27 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
modelRef.object.inputModel.setState(info.inputState);
|
||||
}
|
||||
|
||||
await this.updateModel(modelRef);
|
||||
await this.showModel(modelRef);
|
||||
}
|
||||
|
||||
private async clear(): Promise<void> {
|
||||
|
||||
// Grab the widget's latest view state because it will be loaded back into the widget
|
||||
this.updateViewState();
|
||||
await this.updateModel(undefined);
|
||||
await this.showModel(undefined);
|
||||
|
||||
// Update the toolbar context with new sessionId
|
||||
this.updateActions();
|
||||
}
|
||||
|
||||
async loadSession(sessionId: URI): Promise<IChatModel | undefined> {
|
||||
|
||||
const sessionType = getChatSessionType(sessionId);
|
||||
if (sessionType !== localChatSessionType) {
|
||||
await this.chatSessionsService.canResolveChatSession(sessionId);
|
||||
}
|
||||
|
||||
const newModelRef = await this.chatService.loadSessionForResource(sessionId, ChatAgentLocation.Chat, CancellationToken.None);
|
||||
return this.updateModel(newModelRef);
|
||||
return this.showModel(newModelRef);
|
||||
}
|
||||
|
||||
focusInput(): void {
|
||||
@ -440,6 +465,9 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
remainingHeight -= this.sessionsContainer.offsetHeight;
|
||||
}
|
||||
|
||||
// Title Control
|
||||
remainingHeight -= this.titleControl?.getHeight() ?? 0;
|
||||
|
||||
// Chat Widget
|
||||
this._widget.layout(remainingHeight, width);
|
||||
}
|
||||
@ -494,4 +522,15 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
|
||||
this._widget.unlockFromCodingAgent();
|
||||
}
|
||||
}
|
||||
|
||||
override get singleViewPaneContainerTitle(): string | undefined {
|
||||
if (this.titleControl) {
|
||||
const titleControlTitle = this.titleControl.getSingleViewPaneContainerTitle();
|
||||
if (titleControlTitle) {
|
||||
return titleControlTitle;
|
||||
}
|
||||
}
|
||||
|
||||
return super.singleViewPaneContainerTitle;
|
||||
}
|
||||
}
|
||||
|
||||
180
src/vs/workbench/contrib/chat/browser/chatViewTitleControl.ts
Normal file
180
src/vs/workbench/contrib/chat/browser/chatViewTitleControl.ts
Normal file
@ -0,0 +1,180 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import './media/chatViewTitleControl.css';
|
||||
import { h } from '../../../../base/browser/dom.js';
|
||||
import { Emitter } from '../../../../base/common/event.js';
|
||||
import { Disposable, MutableDisposable } from '../../../../base/common/lifecycle.js';
|
||||
import { localize } from '../../../../nls.js';
|
||||
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
|
||||
import { IViewDescriptorService, IViewContainerModel } from '../../../common/views.js';
|
||||
import { ActivityBarPosition, LayoutSettings } from '../../../services/layout/browser/layoutService.js';
|
||||
import { IChatModel } from '../common/chatModel.js';
|
||||
import { ChatViewId } from './chat.js';
|
||||
import { ChatConfiguration } from '../common/constants.js';
|
||||
import { MenuWorkbenchToolBar } from '../../../../platform/actions/browser/toolbar.js';
|
||||
import { MenuId } from '../../../../platform/actions/common/actions.js';
|
||||
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
|
||||
|
||||
export interface IChatViewTitleDelegate {
|
||||
updateTitle(title: string): void;
|
||||
}
|
||||
|
||||
export class ChatViewTitleControl extends Disposable {
|
||||
|
||||
private static readonly DEFAULT_TITLE = localize('chat', "Chat Session");
|
||||
|
||||
private readonly _onDidChangeHeight = this._register(new Emitter<void>());
|
||||
readonly onDidChangeHeight = this._onDidChangeHeight.event;
|
||||
|
||||
private get viewContainerModel(): IViewContainerModel | undefined {
|
||||
const viewContainer = this.viewDescriptorService.getViewContainerByViewId(ChatViewId);
|
||||
if (viewContainer) {
|
||||
return this.viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private title: string | undefined = undefined;
|
||||
|
||||
private titleContainer: HTMLElement | undefined;
|
||||
private titleLabel: HTMLElement | undefined;
|
||||
|
||||
private model: IChatModel | undefined;
|
||||
private modelDisposables = this._register(new MutableDisposable());
|
||||
|
||||
private lastKnownHeight = 0;
|
||||
|
||||
constructor(
|
||||
private readonly container: HTMLElement,
|
||||
private readonly delegate: IChatViewTitleDelegate,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.render(this.container);
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
|
||||
// Update when views change in container
|
||||
if (this.viewContainerModel) {
|
||||
this._register(this.viewContainerModel.onDidAddVisibleViewDescriptors(() => this.doUpdate()));
|
||||
this._register(this.viewContainerModel.onDidRemoveVisibleViewDescriptors(() => this.doUpdate()));
|
||||
}
|
||||
|
||||
// Update on configuration changes
|
||||
this._register(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (
|
||||
e.affectsConfiguration(LayoutSettings.ACTIVITY_BAR_LOCATION) ||
|
||||
e.affectsConfiguration(ChatConfiguration.ChatViewTitleEnabled)
|
||||
) {
|
||||
this.doUpdate();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private render(parent: HTMLElement): void {
|
||||
const elements = h('div.chat-view-title-container', [
|
||||
h('div.chat-view-title-toolbar@toolbar'),
|
||||
h('span.chat-view-title-label@label'),
|
||||
]);
|
||||
|
||||
this._register(this.instantiationService.createInstance(MenuWorkbenchToolBar, elements.toolbar, MenuId.ChatViewSessionTitleToolbar, {}));
|
||||
|
||||
this.titleContainer = elements.root;
|
||||
this.titleLabel = elements.label;
|
||||
|
||||
parent.appendChild(this.titleContainer);
|
||||
}
|
||||
|
||||
update(model: IChatModel | undefined): void {
|
||||
this.model = model;
|
||||
|
||||
this.modelDisposables.value = model?.onDidChange(e => {
|
||||
if (e.kind === 'setCustomTitle' || e.kind === 'addRequest') {
|
||||
this.doUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
this.doUpdate();
|
||||
}
|
||||
|
||||
private doUpdate(): void {
|
||||
this.title = this.model?.title;
|
||||
|
||||
this.delegate.updateTitle(this.getTitleWithPrefix());
|
||||
|
||||
this.updateTitle(this.title ?? ChatViewTitleControl.DEFAULT_TITLE);
|
||||
}
|
||||
|
||||
private updateTitle(title: string): void {
|
||||
if (!this.titleContainer || !this.titleLabel) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.titleContainer.classList.toggle('visible', this.shouldRender());
|
||||
this.titleLabel.textContent = title;
|
||||
|
||||
const currentHeight = this.getHeight();
|
||||
if (currentHeight !== this.lastKnownHeight) {
|
||||
this.lastKnownHeight = currentHeight;
|
||||
|
||||
this._onDidChangeHeight.fire();
|
||||
}
|
||||
}
|
||||
|
||||
private shouldRender(): boolean {
|
||||
if (!this.isEnabled()) {
|
||||
return false; // title hidden via setting
|
||||
}
|
||||
|
||||
if (this.viewContainerModel && this.viewContainerModel.visibleViewDescriptors.length > 1) {
|
||||
return false; // multiple views visible, chat view shows a title already
|
||||
}
|
||||
|
||||
if (this.configurationService.getValue<ActivityBarPosition>(LayoutSettings.ACTIVITY_BAR_LOCATION) !== ActivityBarPosition.DEFAULT) {
|
||||
return false; // activity bar not in default location, view title shown already
|
||||
}
|
||||
|
||||
return !!this.model?.title;
|
||||
}
|
||||
|
||||
private isEnabled(): boolean {
|
||||
return this.configurationService.getValue<boolean>(ChatConfiguration.ChatViewTitleEnabled) === true;
|
||||
}
|
||||
|
||||
getSingleViewPaneContainerTitle(): string | undefined {
|
||||
if (
|
||||
!this.isEnabled() || // title disabled
|
||||
this.shouldRender() // title is rendered in the view, do not repeat
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.getTitleWithPrefix();
|
||||
}
|
||||
|
||||
private getTitleWithPrefix(): string {
|
||||
if (this.title) {
|
||||
return localize('chatTitleWithPrefixCustom', "Chat: {0}", this.title);
|
||||
}
|
||||
|
||||
return ChatViewTitleControl.DEFAULT_TITLE;
|
||||
}
|
||||
|
||||
getHeight(): number {
|
||||
if (!this.titleContainer || this.titleContainer.style.display === 'none') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this.titleContainer.offsetHeight;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.chat-viewpane {
|
||||
|
||||
.chat-view-title-container {
|
||||
display: none;
|
||||
padding: 8px 16px;
|
||||
border-bottom: 1px solid var(--vscode-sideBarSectionHeader-border);
|
||||
align-items: center;
|
||||
|
||||
.chat-view-title-label {
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
color: var(--vscode-descriptionForeground);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-view-title-container.visible {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
@ -25,6 +25,7 @@ export enum ChatConfiguration {
|
||||
ShowAgentSessionsViewDescription = 'chat.showAgentSessionsViewDescription',
|
||||
NotifyWindowOnResponseReceived = 'chat.notifyWindowOnResponseReceived',
|
||||
ChatViewRecentSessionsEnabled = 'chat.recentSessions.enabled',
|
||||
ChatViewTitleEnabled = 'chat.viewTitle.enabled',
|
||||
SubagentToolCustomAgents = 'chat.customAgentInSubagent.enabled',
|
||||
ShowCodeBlockProgressAnimation = 'chat.agent.codeBlockProgress',
|
||||
RestoreLastPanelSession = 'chat.restoreLastPanelSession',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user