Skip to content

Commit d57d4eb

Browse files
authored
Agent debug panel UI cleanup (#297571)
1 parent 07de89b commit d57d4eb

8 files changed

Lines changed: 114 additions & 116 deletions

File tree

src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugFileListRenderer.ts renamed to src/vs/workbench/contrib/chat/browser/chatDebug/chatCustomizationDiscoveryRenderer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { ILabelService } from '../../../../../platform/label/common/label.js';
2222
import { IOpenerService } from '../../../../../platform/opener/common/opener.js';
2323
import { IChatDebugEventFileListContent } from '../../common/chatDebugService.js';
2424
import { InlineAnchorWidget } from '../widget/chatContentParts/chatInlineAnchorWidget.js';
25-
import { setupCollapsibleToggle } from './chatDebugMessageContentRenderer.js';
25+
import { setupCollapsibleToggle } from './chatDebugCollapsible.js';
2626

2727
const $ = DOM.$;
2828

@@ -153,7 +153,7 @@ function appendLocationBadge(row: HTMLElement, file: { extensionId?: string }, b
153153
/**
154154
* Render a file list resolved content as a rich HTML element.
155155
*/
156-
export function renderFileListContent(content: IChatDebugEventFileListContent, openerService: IOpenerService, modelService: IModelService, languageService: ILanguageService, hoverService: IHoverService, labelService: ILabelService): { element: HTMLElement; disposables: DisposableStore } {
156+
export function renderCustomizationDiscoveryContent(content: IChatDebugEventFileListContent, openerService: IOpenerService, modelService: IModelService, languageService: ILanguageService, hoverService: IHoverService, labelService: ILabelService): { element: HTMLElement; disposables: DisposableStore } {
157157
const disposables = new DisposableStore();
158158
const container = $('div.chat-debug-file-list');
159159
container.tabIndex = 0;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as DOM from '../../../../../base/browser/dom.js';
7+
import { Codicon } from '../../../../../base/common/codicons.js';
8+
import { DisposableStore } from '../../../../../base/common/lifecycle.js';
9+
import { ThemeIcon } from '../../../../../base/common/themables.js';
10+
import { IChatDebugMessageSection } from '../../common/chatDebugService.js';
11+
12+
const $ = DOM.$;
13+
14+
/**
15+
* Wire up a collapsible toggle on a chevron+header+content triple.
16+
* Handles icon switching and display toggling.
17+
*/
18+
export function setupCollapsibleToggle(chevron: HTMLElement, header: HTMLElement, contentEl: HTMLElement, disposables: DisposableStore, initiallyCollapsed: boolean = false): void {
19+
let collapsed = initiallyCollapsed;
20+
21+
// Accessibility: make header keyboard-focusable and expose toggle semantics
22+
header.tabIndex = 0;
23+
header.role = 'button';
24+
chevron.setAttribute('aria-hidden', 'true');
25+
26+
const updateState = () => {
27+
DOM.clearNode(chevron);
28+
const icon = collapsed ? Codicon.chevronRight : Codicon.chevronDown;
29+
chevron.classList.add(...ThemeIcon.asClassName(icon).split(' '));
30+
contentEl.style.display = collapsed ? 'none' : 'block';
31+
header.style.borderRadius = collapsed ? '' : '3px 3px 0 0';
32+
header.setAttribute('aria-expanded', String(!collapsed));
33+
};
34+
35+
updateState();
36+
37+
disposables.add(DOM.addDisposableListener(header, DOM.EventType.CLICK, () => {
38+
collapsed = !collapsed;
39+
chevron.className = 'chat-debug-message-section-chevron';
40+
updateState();
41+
}));
42+
43+
disposables.add(DOM.addDisposableListener(header, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => {
44+
if (e.key === 'Enter' || e.key === ' ') {
45+
e.preventDefault();
46+
header.click();
47+
}
48+
}));
49+
}
50+
51+
/**
52+
* Render a collapsible section with a clickable header and pre-formatted content
53+
* wrapped in a scrollable element.
54+
*/
55+
export function renderCollapsibleSection(parent: HTMLElement, section: IChatDebugMessageSection, disposables: DisposableStore, initiallyCollapsed: boolean = false): void {
56+
const sectionEl = DOM.append(parent, $('div.chat-debug-message-section'));
57+
58+
const header = DOM.append(sectionEl, $('div.chat-debug-message-section-header'));
59+
60+
const chevron = DOM.append(header, $(`span.chat-debug-message-section-chevron`));
61+
DOM.append(header, $('span.chat-debug-message-section-title', undefined, section.name));
62+
63+
const contentEl = $('pre.chat-debug-message-section-content');
64+
contentEl.textContent = section.content;
65+
contentEl.tabIndex = 0;
66+
67+
const wrapper = DOM.append(sectionEl, $('div.chat-debug-message-section-content-wrapper'));
68+
wrapper.appendChild(contentEl);
69+
70+
setupCollapsibleToggle(chevron, header, wrapper, disposables, initiallyCollapsed);
71+
}

src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugDetailPanel.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { IUntitledTextResourceEditorInput } from '../../../../common/editor.js';
2020
import { IEditorService } from '../../../../services/editor/common/editorService.js';
2121
import { IChatDebugEvent, IChatDebugService } from '../../common/chatDebugService.js';
2222
import { formatEventDetail } from './chatDebugEventDetailRenderer.js';
23-
import { renderFileListContent, fileListToPlainText } from './chatDebugFileListRenderer.js';
23+
import { renderCustomizationDiscoveryContent, fileListToPlainText } from './chatCustomizationDiscoveryRenderer.js';
2424
import { renderUserMessageContent, renderAgentResponseContent, messageEventToPlainText, renderResolvedMessageContent, resolvedMessageToPlainText } from './chatDebugMessageContentRenderer.js';
2525

2626
const $ = DOM.$;
@@ -36,6 +36,7 @@ export class ChatDebugDetailPanel extends Disposable {
3636
readonly onDidHide = this._onDidHide.event;
3737

3838
readonly element: HTMLElement;
39+
private readonly contentContainer: HTMLElement;
3940
private readonly detailDisposables = this._register(new DisposableStore());
4041
private currentDetailText: string = '';
4142
private currentDetailEventId: string | undefined;
@@ -51,6 +52,7 @@ export class ChatDebugDetailPanel extends Disposable {
5152
) {
5253
super();
5354
this.element = DOM.append(parent, $('.chat-debug-detail-panel'));
55+
this.contentContainer = $('.chat-debug-detail-content');
5456
DOM.hide(this.element);
5557

5658
// Handle Ctrl+A / Cmd+A to select all within the detail panel
@@ -83,10 +85,12 @@ export class ChatDebugDetailPanel extends Disposable {
8385

8486
DOM.show(this.element);
8587
DOM.clearNode(this.element);
88+
DOM.clearNode(this.contentContainer);
8689
this.detailDisposables.clear();
8790

8891
// Header with action buttons
8992
const header = DOM.append(this.element, $('.chat-debug-detail-header'));
93+
this.element.appendChild(this.contentContainer);
9094

9195
const fullScreenButton = this.detailDisposables.add(new Button(header, { ariaLabel: localize('chatDebug.openInEditor', "Open in Editor"), title: localize('chatDebug.openInEditor', "Open in Editor") }));
9296
fullScreenButton.element.classList.add('chat-debug-detail-button');
@@ -112,27 +116,27 @@ export class ChatDebugDetailPanel extends Disposable {
112116
if (resolved && resolved.kind === 'fileList') {
113117
this.currentDetailText = fileListToPlainText(resolved);
114118
const { element: contentEl, disposables: contentDisposables } = this.instantiationService.invokeFunction(accessor =>
115-
renderFileListContent(resolved, this.openerService, accessor.get(IModelService), accessor.get(ILanguageService), this.hoverService, accessor.get(ILabelService))
119+
renderCustomizationDiscoveryContent(resolved, this.openerService, accessor.get(IModelService), accessor.get(ILanguageService), this.hoverService, accessor.get(ILabelService))
116120
);
117121
this.detailDisposables.add(contentDisposables);
118-
this.element.appendChild(contentEl);
122+
this.contentContainer.appendChild(contentEl);
119123
} else if (resolved && resolved.kind === 'message') {
120124
this.currentDetailText = resolvedMessageToPlainText(resolved);
121125
const { element: contentEl, disposables: contentDisposables } = renderResolvedMessageContent(resolved);
122126
this.detailDisposables.add(contentDisposables);
123-
this.element.appendChild(contentEl);
127+
this.contentContainer.appendChild(contentEl);
124128
} else if (event.kind === 'userMessage') {
125129
this.currentDetailText = messageEventToPlainText(event);
126130
const { element: contentEl, disposables: contentDisposables } = renderUserMessageContent(event);
127131
this.detailDisposables.add(contentDisposables);
128-
this.element.appendChild(contentEl);
132+
this.contentContainer.appendChild(contentEl);
129133
} else if (event.kind === 'agentResponse') {
130134
this.currentDetailText = messageEventToPlainText(event);
131135
const { element: contentEl, disposables: contentDisposables } = renderAgentResponseContent(event);
132136
this.detailDisposables.add(contentDisposables);
133-
this.element.appendChild(contentEl);
137+
this.contentContainer.appendChild(contentEl);
134138
} else {
135-
const pre = DOM.append(this.element, $('pre'));
139+
const pre = DOM.append(this.contentContainer, $('pre'));
136140
pre.tabIndex = 0;
137141
if (resolved) {
138142
this.currentDetailText = resolved.value;
@@ -147,6 +151,7 @@ export class ChatDebugDetailPanel extends Disposable {
147151
this.currentDetailEventId = undefined;
148152
DOM.hide(this.element);
149153
DOM.clearNode(this.element);
154+
DOM.clearNode(this.contentContainer);
150155
this.detailDisposables.clear();
151156
this._onDidHide.fire();
152157
}

src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugHomeView.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as DOM from '../../../../../base/browser/dom.js';
7-
import { DomScrollableElement } from '../../../../../base/browser/ui/scrollbar/scrollableElement.js';
87
import { Codicon } from '../../../../../base/common/codicons.js';
98
import { Emitter } from '../../../../../base/common/event.js';
109
import { Disposable, DisposableStore } from '../../../../../base/common/lifecycle.js';
@@ -26,7 +25,6 @@ export class ChatDebugHomeView extends Disposable {
2625

2726
readonly container: HTMLElement;
2827
private readonly scrollContent: HTMLElement;
29-
private readonly scrollable: DomScrollableElement;
3028
private readonly renderDisposables = this._register(new DisposableStore());
3129

3230
constructor(
@@ -37,9 +35,7 @@ export class ChatDebugHomeView extends Disposable {
3735
) {
3836
super();
3937
this.container = DOM.append(parent, $('.chat-debug-home'));
40-
this.scrollContent = $('div.chat-debug-home-content');
41-
this.scrollable = this._register(new DomScrollableElement(this.scrollContent, {}));
42-
DOM.append(this.container, this.scrollable.getDomNode());
38+
this.scrollContent = DOM.append(this.container, $('div.chat-debug-home-content'));
4339
}
4440

4541
show(): void {
@@ -159,7 +155,5 @@ export class ChatDebugHomeView extends Disposable {
159155
}
160156
}));
161157
}
162-
163-
this.scrollable.scanDomNode();
164158
}
165159
}

src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugLogsView.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export class ChatDebugLogsView extends Disposable {
110110

111111
// View mode toggle
112112
this.viewModeToggle = this._register(new Button(this.headerContainer, { ...defaultButtonStyles, secondary: true, title: localize('chatDebug.toggleViewMode', "Toggle between list and tree view") }));
113-
this.viewModeToggle.element.classList.add('chat-debug-view-mode-toggle');
113+
this.viewModeToggle.element.classList.add('chat-debug-view-mode-toggle', 'monaco-text-button');
114114
this.updateViewModeToggle();
115115
this._register(this.viewModeToggle.onDidClick(() => {
116116
this.toggleViewMode();

src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugMessageContentRenderer.ts

Lines changed: 2 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -4,82 +4,13 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as DOM from '../../../../../base/browser/dom.js';
7-
import { DomScrollableElement } from '../../../../../base/browser/ui/scrollbar/scrollableElement.js';
8-
import { Codicon } from '../../../../../base/common/codicons.js';
97
import { DisposableStore } from '../../../../../base/common/lifecycle.js';
10-
import { ThemeIcon } from '../../../../../base/common/themables.js';
118
import { localize } from '../../../../../nls.js';
12-
import { IChatDebugMessageSection, IChatDebugUserMessageEvent, IChatDebugAgentResponseEvent, IChatDebugEventMessageContent } from '../../common/chatDebugService.js';
9+
import { IChatDebugUserMessageEvent, IChatDebugAgentResponseEvent, IChatDebugEventMessageContent } from '../../common/chatDebugService.js';
10+
import { renderCollapsibleSection } from './chatDebugCollapsible.js';
1311

1412
const $ = DOM.$;
1513

16-
/**
17-
* Wire up a collapsible toggle on a chevron+header+content triple.
18-
* Handles icon switching and display toggling.
19-
*/
20-
export function setupCollapsibleToggle(chevron: HTMLElement, header: HTMLElement, contentEl: HTMLElement, disposables: DisposableStore, initiallyCollapsed: boolean = false): void {
21-
let collapsed = initiallyCollapsed;
22-
23-
// Accessibility: make header keyboard-focusable and expose toggle semantics
24-
header.tabIndex = 0;
25-
header.role = 'button';
26-
chevron.setAttribute('aria-hidden', 'true');
27-
28-
const updateState = () => {
29-
DOM.clearNode(chevron);
30-
const icon = collapsed ? Codicon.chevronRight : Codicon.chevronDown;
31-
chevron.classList.add(...ThemeIcon.asClassName(icon).split(' '));
32-
contentEl.style.display = collapsed ? 'none' : 'block';
33-
header.style.borderRadius = collapsed ? '' : '3px 3px 0 0';
34-
header.setAttribute('aria-expanded', String(!collapsed));
35-
};
36-
37-
updateState();
38-
39-
disposables.add(DOM.addDisposableListener(header, DOM.EventType.CLICK, () => {
40-
collapsed = !collapsed;
41-
chevron.className = 'chat-debug-message-section-chevron';
42-
updateState();
43-
}));
44-
45-
disposables.add(DOM.addDisposableListener(header, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => {
46-
if (e.key === 'Enter' || e.key === ' ') {
47-
e.preventDefault();
48-
header.click();
49-
}
50-
}));
51-
}
52-
53-
/**
54-
* Render a collapsible section with a clickable header and pre-formatted content.
55-
*/
56-
function renderCollapsibleSection(parent: HTMLElement, section: IChatDebugMessageSection, disposables: DisposableStore, initiallyCollapsed: boolean = false): void {
57-
const sectionEl = DOM.append(parent, $('div.chat-debug-message-section'));
58-
59-
const header = DOM.append(sectionEl, $('div.chat-debug-message-section-header'));
60-
61-
const chevron = DOM.append(header, $(`span.chat-debug-message-section-chevron`));
62-
DOM.append(header, $('span.chat-debug-message-section-title', undefined, section.name));
63-
64-
const contentEl = $('pre.chat-debug-message-section-content');
65-
contentEl.textContent = section.content;
66-
contentEl.tabIndex = 0;
67-
68-
const scrollable = new DomScrollableElement(contentEl, {});
69-
disposables.add(scrollable);
70-
71-
const wrapper = scrollable.getDomNode();
72-
wrapper.classList.add('chat-debug-message-section-content-wrapper');
73-
DOM.append(sectionEl, wrapper);
74-
75-
setupCollapsibleToggle(chevron, header, wrapper, disposables, initiallyCollapsed);
76-
77-
// Scan after toggle so scrollbar dimensions are correct when expanded
78-
disposables.add(DOM.addDisposableListener(header, DOM.EventType.CLICK, () => {
79-
scrollable.scanDomNode();
80-
}));
81-
}
82-
8314
/**
8415
* Render a user message event with collapsible prompt sections.
8516
*/

src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugOverviewView.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import * as DOM from '../../../../../base/browser/dom.js';
77
import { BreadcrumbsWidget } from '../../../../../base/browser/ui/breadcrumbs/breadcrumbsWidget.js';
88
import { Button } from '../../../../../base/browser/ui/button/button.js';
9-
import { DomScrollableElement } from '../../../../../base/browser/ui/scrollbar/scrollableElement.js';
109
import { Codicon } from '../../../../../base/common/codicons.js';
1110
import { Emitter } from '../../../../../base/common/event.js';
1211
import { Disposable, DisposableStore } from '../../../../../base/common/lifecycle.js';
@@ -37,7 +36,6 @@ export class ChatDebugOverviewView extends Disposable {
3736

3837
readonly container: HTMLElement;
3938
private readonly content: HTMLElement;
40-
private readonly scrollable: DomScrollableElement;
4139
private readonly breadcrumbWidget: BreadcrumbsWidget;
4240
private readonly loadDisposables = this._register(new DisposableStore());
4341

@@ -71,12 +69,7 @@ export class ChatDebugOverviewView extends Disposable {
7169
}
7270
}));
7371

74-
this.content = $('.chat-debug-overview-content');
75-
this.scrollable = this._register(new DomScrollableElement(this.content, {}));
76-
const scrollDom = this.scrollable.getDomNode();
77-
scrollDom.style.flex = '1';
78-
scrollDom.style.minHeight = '0';
79-
DOM.append(this.container, scrollDom);
72+
this.content = DOM.append(this.container, $('.chat-debug-overview-content'));
8073
}
8174

8275
setSession(sessionResource: URI): void {
@@ -152,7 +145,6 @@ export class ChatDebugOverviewView extends Disposable {
152145
const events = this.chatDebugService.getEvents(this.currentSessionResource);
153146
this.renderDerivedOverview(events, this.isFirstLoad);
154147
this.isFirstLoad = false;
155-
this.scrollable.scanDomNode();
156148
}
157149

158150
private renderSessionDetails(sessionUri: URI): void {

0 commit comments

Comments
 (0)