From 7460c38f957e69e8c420b1dd4bfb7a5c85f0cfbf Mon Sep 17 00:00:00 2001 From: Vijay Upadya <41652029+vijayupadya@users.noreply.github.com> Date: Mon, 29 Sep 2025 02:35:06 -0700 Subject: [PATCH] File icon display handling in chat sessions (#268364) * Re-add the chat session icons * update comment * override global file icon hiding for chat sessions * Consolidate font-family * Remove !important for font * move back to use custom icon * Switch to use IconLabel. * remove comment * Changes based on PR feedback to remove color and custom spinning rule * update comment * small nits --------- Co-authored-by: vijay upadya Co-authored-by: BeniBenj --- .../chatSessions/view/sessionsTreeRenderer.ts | 103 ++++-------------- .../chatSessions/view/sessionsViewPane.ts | 3 +- .../chat/browser/media/chatSessions.css | 16 ++- 3 files changed, 37 insertions(+), 85 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatSessions/view/sessionsTreeRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatSessions/view/sessionsTreeRenderer.ts index f209316b91e..8fb06af78db 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSessions/view/sessionsTreeRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSessions/view/sessionsTreeRenderer.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import * as DOM from '../../../../../../base/browser/dom.js'; -import { $, append, getActiveWindow } from '../../../../../../base/browser/dom.js'; +import { $, append } from '../../../../../../base/browser/dom.js'; import { StandardKeyboardEvent } from '../../../../../../base/browser/keyboardEvent.js'; import { ActionBar } from '../../../../../../base/browser/ui/actionbar/actionbar.js'; import { InputBox, MessageType } from '../../../../../../base/browser/ui/inputbox/inputBox.js'; import { IAsyncDataSource, ITreeNode, ITreeRenderer } from '../../../../../../base/browser/ui/tree/tree.js'; import { timeout } from '../../../../../../base/common/async.js'; import { Codicon } from '../../../../../../base/common/codicons.js'; -import { FuzzyScore } from '../../../../../../base/common/filters.js'; +import { FuzzyScore, createMatches } from '../../../../../../base/common/filters.js'; import { createSingleCallFunction } from '../../../../../../base/common/functional.js'; import { isMarkdownString } from '../../../../../../base/common/htmlContent.js'; import { KeyCode } from '../../../../../../base/common/keyCodes.js'; @@ -19,7 +19,6 @@ import { Disposable, DisposableStore, IDisposable, toDisposable } from '../../.. import { MarshalledId } from '../../../../../../base/common/marshallingIds.js'; import Severity from '../../../../../../base/common/severity.js'; import { ThemeIcon } from '../../../../../../base/common/themables.js'; -import { URI } from '../../../../../../base/common/uri.js'; import { MarkdownRenderer } from '../../../../../../editor/browser/widget/markdownRenderer/browser/markdownRenderer.js'; import * as nls from '../../../../../../nls.js'; import { getActionBarActions } from '../../../../../../platform/actions/browser/menuEntryActionViewItem.js'; @@ -29,11 +28,10 @@ import { IContextKeyService } from '../../../../../../platform/contextkey/common import { IContextViewService } from '../../../../../../platform/contextview/browser/contextView.js'; import { IHoverService } from '../../../../../../platform/hover/browser/hover.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; -import { ILogService } from '../../../../../../platform/log/common/log.js'; import product from '../../../../../../platform/product/common/product.js'; import { defaultInputBoxStyles } from '../../../../../../platform/theme/browser/defaultStyles.js'; -import { IThemeService } from '../../../../../../platform/theme/common/themeService.js'; import { IResourceLabel, ResourceLabels } from '../../../../../browser/labels.js'; +import { IconLabel } from '../../../../../../base/browser/ui/iconLabel/iconLabel.js'; import { IEditableData } from '../../../../../common/views.js'; import { IEditorGroupsService } from '../../../../../services/editor/common/editorGroupsService.js'; import { IChatService } from '../../../common/chatService.js'; @@ -51,13 +49,14 @@ import { getLocalHistoryDateFormatter } from '../../../../localHistory/browser/l interface ISessionTemplateData { readonly container: HTMLElement; - readonly resourceLabel: IResourceLabel; + readonly iconLabel: IconLabel; readonly actionBar: ActionBar; readonly elementDisposable: DisposableStore; readonly timestamp: HTMLElement; readonly descriptionRow: HTMLElement; readonly descriptionLabel: HTMLElement; readonly statisticsLabel: HTMLElement; + readonly customIcon: HTMLElement; } export interface IGettingStartedItem { @@ -110,13 +109,9 @@ export class GettingStartedRenderer implements IListRenderer { static readonly TEMPLATE_ID = 'session'; - private appliedIconColorStyles = new Set(); private markdownRenderer: MarkdownRenderer; constructor( - private readonly labels: ResourceLabels, - @IThemeService private readonly themeService: IThemeService, - @ILogService private readonly logService: ILogService, @IContextViewService private readonly contextViewService: IContextViewService, @IConfigurationService private readonly configurationService: IConfigurationService, @IChatSessionsService private readonly chatSessionsService: IChatSessionsService, @@ -130,56 +125,9 @@ export class SessionsRenderer extends Disposable implements ITreeRenderer { - this.appliedIconColorStyles.clear(); - })); - this.markdownRenderer = instantiationService.createInstance(MarkdownRenderer, {}); } - private applyIconColorStyle(iconId: string, colorId: string): void { - const styleKey = `${iconId}-${colorId}`; - if (this.appliedIconColorStyles.has(styleKey)) { - return; // Already applied - } - - const colorTheme = this.themeService.getColorTheme(); - const color = colorTheme.getColor(colorId); - - if (color) { - // Target the ::before pseudo-element where the actual icon is rendered - const css = `.monaco-workbench .chat-session-item .monaco-icon-label.codicon-${iconId}::before { color: ${color} !important; }`; - const activeWindow = getActiveWindow(); - - const styleId = `chat-sessions-icon-${styleKey}`; - const existingStyle = activeWindow.document.getElementById(styleId); - if (existingStyle) { - existingStyle.textContent = css; - } else { - const styleElement = activeWindow.document.createElement('style'); - styleElement.id = styleId; - styleElement.textContent = css; - activeWindow.document.head.appendChild(styleElement); - - // Clean up on dispose - this._register({ - dispose: () => { - const activeWin = getActiveWindow(); - const style = activeWin.document.getElementById(styleId); - if (style) { - style.remove(); - } - } - }); - } - - this.appliedIconColorStyles.add(styleKey); - } else { - this.logService.debug('No color found for colorId:', colorId); - } - } - get templateId(): string { return SessionsRenderer.TEMPLATE_ID; } @@ -189,7 +137,9 @@ export class SessionsRenderer extends Disposable implements ITreeRenderer(ChatConfiguration.ShowAgentSessionsViewDescription) && session.provider.chatSessionType !== 'local'; if (renderDescriptionOnSecondRow && session.description) { templateData.container.classList.toggle('multiline', true); @@ -305,17 +251,17 @@ export class SessionsRenderer extends Disposable implements ITreeRenderer, _index: number, templateData: ISessionTemplateData): void { templateData.elementDisposable.clear(); - templateData.resourceLabel.clear(); templateData.actionBar.clear(); } @@ -531,7 +476,7 @@ export class SessionsRenderer extends Disposable implements ITreeRenderer { diff --git a/src/vs/workbench/contrib/chat/browser/media/chatSessions.css b/src/vs/workbench/contrib/chat/browser/media/chatSessions.css index db3744ca4a3..1bd6b83280a 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chatSessions.css +++ b/src/vs/workbench/contrib/chat/browser/media/chatSessions.css @@ -169,8 +169,14 @@ text-align: center; } -.chat-sessions-tree-container .chat-session-item .monaco-icon-label.codicon-loading::before { - animation: codicon-spin 1.5s steps(30) infinite; +/* Chat session icon */ +.chat-sessions-tree-container .chat-session-item .chat-session-custom-icon { + flex-shrink: 0; + width: 16px; + height: 16px; + margin-right: 6px; + font-size: 16px; + display: flex; } /* Timestamp styling - similar to timeline pane */ @@ -229,8 +235,10 @@ /* Hide twisties for elements that don't have children */ .chat-sessions-tree-container .monaco-list-row .monaco-tl-twistie { - visibility: hidden; - width: 0; + /* Ultra-small indent to separate parent/child without large gutter */ + visibility: hidden; /* keep layout space */ + width: 3px; + min-width: 3px; padding: 0; margin: 0; }