diff --git a/src/vs/workbench/contrib/chat/browser/chatSessions.ts b/src/vs/workbench/contrib/chat/browser/chatSessions.ts index 08196c0d117..0a6e831a882 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSessions.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSessions.ts @@ -34,7 +34,7 @@ import { FuzzyScore } from '../../../../base/common/filters.js'; import { ResourceLabels, IResourceLabel } from '../../../browser/labels.js'; import { ActionBar } from '../../../../base/browser/ui/actionbar/actionbar.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; -import { append, $, getActiveWindow } from '../../../../base/browser/dom.js'; +import { append, $, getActiveWindow, clearNode } from '../../../../base/browser/dom.js'; import { URI } from '../../../../base/common/uri.js'; import { IEditorGroupsService, IEditorGroup } from '../../../services/editor/common/editorGroupsService.js'; import { GroupModelChangeKind } from '../../../common/editor.js'; @@ -673,6 +673,7 @@ class SessionsViewPane extends ViewPane { private treeContainer?: HTMLElement; private dataSource?: SessionsDataSource; private labels?: ResourceLabels; + private messageElement?: HTMLElement; constructor( private readonly provider: IChatSessionItemProvider, @@ -690,6 +691,7 @@ class SessionsViewPane extends ViewPane { @IViewsService private readonly viewsService: IViewsService, @ILogService private readonly logService: ILogService, @IProgressService private readonly progressService: IProgressService, + @IChatSessionsService private readonly chatSessionsService: IChatSessionsService, ) { super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, hoverService); @@ -713,6 +715,84 @@ class SessionsViewPane extends ViewPane { } } + private getProviderDisplayName(): string { + const contributions = this.chatSessionsService.getChatSessionContributions(); + const contribution = contributions.find(c => c.type === this.provider.chatSessionType); + if (contribution) { + return contribution.displayName; + } + return ''; + } + + private showEmptyMessage(): void { + if (!this.messageElement) { + return; + } + + // Only show message for non-local providers + if (this.provider.chatSessionType === 'local') { + this.hideMessage(); + return; + } + + const providerName = this.getProviderDisplayName(); + if (!providerName) { + return; + } + + const messageText = nls.localize('chatSessions.noResults', "No sessions found from {0}", providerName); + + // Clear the message element using DOM utility + clearNode(this.messageElement); + + const messageContainer = append(this.messageElement, $('.no-sessions-message')); + + append(messageContainer, $('.codicon.codicon-info')); + const textElement = append(messageContainer, $('span')); + textElement.textContent = messageText; + + // Show the message element + this.messageElement.style.display = 'block'; + + // Hide the tree + if (this.treeContainer) { + this.treeContainer.style.display = 'none'; + } + } + + private hideMessage(): void { + if (this.messageElement) { + this.messageElement.style.display = 'none'; + } + + // Show the tree + if (this.treeContainer) { + this.treeContainer.style.display = 'block'; + } + } + + /** + * Updates the empty state message based on current tree data. + * Uses the tree's existing data to avoid redundant provider calls. + */ + private updateEmptyStateMessage(): void { + try { + // Check if the tree has the provider node and get its children count + if (this.tree?.hasNode(this.provider)) { + const providerNode = this.tree.getNode(this.provider); + const childCount = providerNode.children?.length || 0; + + if (childCount === 0) { + this.showEmptyMessage(); + } else { + this.hideMessage(); + } + } + } catch (error) { + this.logService.error('Error checking tree data for empty state:', error); + } + } + /** * Refreshes the tree data with progress indication. * Shows a progress indicator while the tree updates its children from the provider. @@ -732,6 +812,9 @@ class SessionsViewPane extends ViewPane { await this.tree!.updateChildren(this.provider); } ); + + // Check for empty state after refresh using tree data + this.updateEmptyStateMessage(); } catch (error) { // Log error but don't throw to avoid breaking the UI this.logService.error('Error refreshing chat sessions tree:', error); @@ -757,6 +840,9 @@ class SessionsViewPane extends ViewPane { await this.tree!.setInput(this.provider); } ); + + // Check for empty state after loading using tree data + this.updateEmptyStateMessage(); } catch (error) { // Log error but don't throw to avoid breaking the UI this.logService.error('Error loading chat sessions data:', error); @@ -766,6 +852,10 @@ class SessionsViewPane extends ViewPane { protected override renderBody(container: HTMLElement): void { super.renderBody(container); + // Create message element for empty state + this.messageElement = append(container, $('.chat-sessions-message')); + this.messageElement.style.display = 'none'; + this.treeContainer = append(container, $('.chat-sessions-tree.show-file-icons')); this.treeContainer.classList.add('file-icon-themable-tree'); @@ -807,6 +897,7 @@ class SessionsViewPane extends ViewPane { // Handle double-click and keyboard selection to open editors this._register(this.tree.onDidOpen(async e => { const element = e.element as IChatSessionItem & { provider: IChatSessionItemProvider }; + if (element && this.isLocalChatSessionItem(element)) { if (element.sessionType === 'editor' && element.editor && element.group) { // Open the chat editor diff --git a/src/vs/workbench/contrib/chat/browser/media/chatSessions.css b/src/vs/workbench/contrib/chat/browser/media/chatSessions.css index b057f0e9e66..358d8d158fc 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chatSessions.css +++ b/src/vs/workbench/contrib/chat/browser/media/chatSessions.css @@ -21,3 +21,22 @@ margin-right: 4px; margin-left: 4px; } + +/* Style for empty state message */ +.chat-sessions-message { + padding: 20px; + text-align: center; + color: var(--vscode-descriptionForeground); +} + +.chat-sessions-message .no-sessions-message { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + font-style: italic; +} + +.chat-sessions-message .no-sessions-message .codicon { + opacity: 0.7; +}