Skip to content

Commit bf119b0

Browse files
authored
Improve chat todo list progress title, ARIA labels, and truncation (microsoft#273158)
* Improve chat todo list progress title, ARIA labels, and truncation; adjust input padding * Reduce bottom padding for chat todo list widget to tighten spacing
1 parent 137e8e2 commit bf119b0

File tree

4 files changed

+28
-21
lines changed

4 files changed

+28
-21
lines changed

src/vs/workbench/contrib/chat/browser/chatContentParts/chatTodoListWidget.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -448,19 +448,19 @@ export class ChatTodoListWidget extends Disposable {
448448
const notStartedTodos = todoList.filter(todo => todo.status === 'not-started');
449449
const firstNotStartedTodo = notStartedTodos.length > 0 ? notStartedTodos[0] : undefined;
450450

451-
const progressText = dom.$('span');
452-
if (totalCount === 0) {
453-
progressText.textContent = localize('chat.todoList.title', 'Todos');
454-
} else {
455-
// Show the current task number (1-indexed): completed + in-progress, or just completed if none in-progress
456-
// Ensure we show at least 1 when tasks exist
457-
const currentTaskNumber = inProgressTodos.length > 0 ? completedCount + 1 : Math.max(1, completedCount);
458-
progressText.textContent = localize('chat.todoList.titleWithProgressExpanded', 'Todos ({0}/{1})', currentTaskNumber, totalCount);
459-
}
460-
titleElement.appendChild(progressText);
451+
// Calculate current task number (1-indexed)
452+
const currentTaskNumber = inProgressTodos.length > 0 ? completedCount + 1 : Math.max(1, completedCount);
453+
const progressCount = totalCount > 0 ? ` (${currentTaskNumber}/${totalCount})` : '';
454+
455+
const titleText = dom.$('span');
456+
titleText.textContent = this._isExpanded
457+
? localize('chat.todoList.title', 'Todos') + progressCount
458+
: progressCount;
459+
titleElement.appendChild(titleText);
460+
461461
const expandButtonLabel = this._isExpanded
462-
? localize('chat.todoList.collapseButtonWithProgress', 'Collapse {0}', progressText.textContent)
463-
: localize('chat.todoList.expandButtonWithProgress', 'Expand {0}', progressText.textContent);
462+
? localize('chat.todoList.collapseButton', 'Collapse Todos {0}', progressCount)
463+
: localize('chat.todoList.expandButton', 'Expand Todos {0}', progressCount);
464464
this.expandoElement.setAttribute('aria-label', expandButtonLabel);
465465
this.expandoElement.setAttribute('aria-expanded', this._isExpanded ? 'true' : 'false');
466466
if (!this._isExpanded) {
@@ -488,6 +488,10 @@ export class ChatTodoListWidget extends Disposable {
488488
const todoText = dom.$('span');
489489
todoText.textContent = todoToShow.title;
490490
todoText.style.verticalAlign = 'middle';
491+
todoText.style.overflow = 'hidden';
492+
todoText.style.textOverflow = 'ellipsis';
493+
todoText.style.whiteSpace = 'nowrap';
494+
todoText.style.minWidth = '0';
491495
titleElement.appendChild(todoText);
492496
}
493497
// Show "Done" when all tasks are completed

src/vs/workbench/contrib/chat/browser/chatInputPart.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2095,7 +2095,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
20952095
followupsHeight: this.followupsContainer.offsetHeight,
20962096
inputPartEditorHeight: Math.min(this._inputEditor.getContentHeight(), this.inputEditorMaxHeight),
20972097
inputPartHorizontalPadding: this.options.renderStyle === 'compact' ? 16 : 32,
2098-
inputPartVerticalPadding: this.options.renderStyle === 'compact' ? 12 : (16 /* entire part */ + 6 /* input container */ + (2 * 4) /* flex gap: edits|input */),
2098+
inputPartVerticalPadding: this.options.renderStyle === 'compact' ? 12 : (16 /* entire part */ + 6 /* input container */ + (1 * 4) /* flex gap: todo|edits|input */),
20992099
attachmentsHeight: this.attachmentsHeight,
21002100
editorBorder: 2,
21012101
inputPartHorizontalPaddingInside: 12,

src/vs/workbench/contrib/chat/browser/media/chat.css

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ have to be updated for changes to the rules above, or to support more deeply nes
10941094
}
10951095

10961096
.interactive-session .interactive-input-part > .chat-todo-list-widget-container .chat-todo-list-widget {
1097-
padding: 6px 8px 6px 12px;
1097+
padding: 6px 8px 5px 12px;
10981098
box-sizing: border-box;
10991099
border: 1px solid var(--vscode-input-border, transparent);
11001100
background-color: var(--vscode-editor-background);
@@ -1186,6 +1186,8 @@ have to be updated for changes to the rules above, or to support more deeply nes
11861186
color: var(--vscode-foreground);
11871187
display: flex;
11881188
align-items: center;
1189+
overflow: hidden;
1190+
text-overflow: ellipsis;
11891191
}
11901192

11911193
.interactive-session .interactive-input-part > .chat-todo-list-widget-container .chat-todo-list-widget .todo-list-container {

src/vs/workbench/contrib/chat/test/browser/chatTodoListWidget.test.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ suite('ChatTodoListWidget Accessibility', () => {
6262

6363
const titleElement = widget.domNode.querySelector('#todo-list-title');
6464
assert.ok(titleElement, 'Should have title element with ID todo-list-title');
65-
assert.ok(titleElement?.textContent?.includes('Todos'));
65+
// When collapsed, title shows progress and current task without "Todos" prefix
66+
assert.ok(titleElement?.textContent, 'Title should have content');
6667

6768
// The todo list container itself acts as the list (no nested ul element)
6869
const todoItems = todoListContainer?.querySelectorAll('li.todo-item');
@@ -113,13 +114,13 @@ suite('ChatTodoListWidget Accessibility', () => {
113114
assert.strictEqual(expandoElement?.getAttribute('aria-expanded'), 'false'); // Should be collapsed due to in-progress task
114115
assert.strictEqual(expandoElement?.getAttribute('aria-controls'), 'todo-list-container');
115116

116-
// The title element should have aria-label with progress information
117+
// The title element should have progress information
117118
const titleElement = expandoElement?.querySelector('.todo-list-title');
118119
assert.ok(titleElement, 'Should have title element');
119120
const titleText = titleElement?.textContent;
120-
// When collapsed, title shows progress and current task: "Todos (2/3) - Second task"
121+
// When collapsed, title shows progress and current task: " (2/3) - Second task"
121122
// Progress is 2/3 because: 1 completed + 1 in-progress (current) = task 2 of 3
122-
assert.ok(titleText?.includes('Todos (2/3)'), `Title should show progress format, but got: "${titleText}"`);
123+
assert.ok(titleText?.includes('(2/3)'), `Title should show progress format, but got: "${titleText}"`);
123124
assert.ok(titleText?.includes('Second task'), `Title should show current task when collapsed, but got: "${titleText}"`);
124125
}); test('hidden status text elements exist for screen readers', () => {
125126
widget.render('test-session');
@@ -178,11 +179,11 @@ suite('ChatTodoListWidget Accessibility', () => {
178179
const titleElement = widget.domNode.querySelector('#todo-list-title');
179180
assert.ok(titleElement, 'Should have title element with ID');
180181

181-
// Title should show progress format: "Todos (2/3)" since one todo is completed and one is in-progress
182-
// When collapsed, it also shows the current task: "Todos (2/3) - Second task"
182+
// Title should show progress format: " (2/3)" since one todo is completed and one is in-progress
183+
// When collapsed, it also shows the current task: " (2/3) - Second task"
183184
// Progress is 2/3 because: 1 completed + 1 in-progress (current) = task 2 of 3
184185
const titleText = titleElement?.textContent;
185-
assert.ok(titleText?.includes('Todos (2/3)'), `Title should show progress format, but got: "${titleText}"`);
186+
assert.ok(titleText?.includes('(2/3)'), `Title should show progress format, but got: "${titleText}"`);
186187
assert.ok(titleText?.includes('Second task'), `Title should show current task when collapsed, but got: "${titleText}"`);
187188

188189
// Verify aria-labelledby connection works

0 commit comments

Comments
 (0)