Skip to content

Conversation

@karthiknadig
Copy link
Member

@karthiknadig karthiknadig commented Jan 27, 2026

fixes #290784
fixes #290807
fixes #290808

Copilot AI review requested due to automatic review settings January 27, 2026 05:52
@karthiknadig karthiknadig self-assigned this Jan 27, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the Chat “question carousel” UI to improve its visual styling and navigation behavior, and introduces a post-submit “summary” view.

Changes:

  • Restyles the question carousel to match chat request visuals (borders, padding, typography) and adds a summary layout.
  • Moves navigation controls into the header and adds a close/skip control.
  • Switches freeform inputs from InputBox to a styled <textarea> and adds answer-summary rendering logic.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

File Description
src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatQuestionCarousel.css Updates carousel layout/styling and adds new styles for header navigation, summary view, and freeform textarea.
src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuestionCarouselPart.ts Refactors carousel rendering (header navigation), adds summary rendering after submit/skip, and replaces freeform InputBox with <textarea>.
Comments suppressed due to low confidence (2)

src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuestionCarouselPart.ts:238

  • ignore() no longer checks carousel.allowSkip, so callers can bypass a non-skippable carousel. Restore the !this.carousel.allowSkip guard (or introduce a separate capability flag if “dismiss without answers” should be allowed independently).
	public ignore(): boolean {
		if (this._isSkipped) {
			return false;
		}

src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuestionCarouselPart.ts:479

  • The freeform <textarea> is not associated with the visible label, so screen readers won’t announce its purpose. Add aria-labelledby pointing to the label (give the label an id) or set an explicit aria-label (localized).
			const freeformContainer = dom.$('.chat-question-freeform');
			const freeformLabel = dom.$('.chat-question-freeform-label');
			freeformLabel.textContent = localize('chat.questionCarousel.orEnterOwn', 'Or enter your own:');
			freeformContainer.appendChild(freeformLabel);

			const freeformTextarea = dom.$<HTMLTextAreaElement>('textarea.chat-question-freeform-textarea');
			freeformTextarea.placeholder = localize('chat.questionCarousel.enterCustomAnswer', 'Enter custom answer');
			freeformTextarea.rows = 1;

			if (previousFreeform !== undefined) {
				freeformTextarea.value = previousFreeform;
			}

			freeformContainer.appendChild(freeformTextarea);
			container.appendChild(freeformContainer);
			this._freeformTextareas.set(question.id, freeformTextarea);
		}

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuestionCarouselPart.ts:497

  • The new freeform <textarea> has only a placeholder and a separate non-<label> element, so it has no programmatic label. Consider using a <label for> + id, or set aria-label/aria-labelledby on the textarea to match the “Or enter your own:” text.
			const freeformContainer = dom.$('.chat-question-freeform');
			const freeformLabel = dom.$('.chat-question-freeform-label');
			freeformLabel.textContent = localize('chat.questionCarousel.orEnterOwn', 'Or enter your own:');
			freeformContainer.appendChild(freeformLabel);

			const freeformTextarea = dom.$<HTMLTextAreaElement>('textarea.chat-question-freeform-textarea');
			freeformTextarea.placeholder = localize('chat.questionCarousel.enterCustomAnswer', 'Enter custom answer');
			freeformTextarea.rows = 1;

			if (previousFreeform !== undefined) {
				freeformTextarea.value = previousFreeform;
			}

			freeformContainer.appendChild(freeformTextarea);
			container.appendChild(freeformContainer);
			this._freeformTextareas.set(question.id, freeformTextarea);

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (2)

src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuestionCarouselPart.ts:91

  • _titlePart is declared as ChatQueryTitlePart | undefined, but it’s used here without a null-check. With strict TS settings this will fail to compile (Object is possibly 'undefined'). Consider using a local const for the created part, or switch these fields to definite assignment (private _titlePart!: ...) since the constructor returns early in the isUsed case.
		this._register(this._titlePart.onDidChangeHeight(() => this._onDidChangeHeight.fire()));

src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuestionCarouselPart.ts:129

  • _prevButton/_nextButton are typed as Button | undefined but are used directly here. This will fail under strictNullChecks. Use local variables when wiring listeners (then assign to the fields), or make these fields definite-assigned (e.g. private _prevButton!: Button) and rely on the early-return for the summary-only path.
		this._register(this._prevButton.onDidClick(() => this.navigate(-1)));
		this._register(this._nextButton.onDidClick(() => this.handleNext()));

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuestionCarouselPart.ts:259

  • hideAndShowSummary() and ignore() duplicate the same “clear interactive state” logic (clearing _inputBoxes/maps, clearing the DOM, firing height change). Extracting a shared helper (e.g. clearInteractiveUI() + showSummary() / showSkippedMessage()) would reduce the chance of these paths drifting over time.
		// Dispose interactive UI disposables before clearing DOM
		this._inputBoxes.clear();
		this._textInputBoxes.clear();
		this._radioInputs.clear();
		this._checkboxInputs.clear();
		this._freeformTextareas.clear();

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

@karthiknadig karthiknadig marked this pull request as ready for review January 27, 2026 18:45
@vs-code-engineering vs-code-engineering bot added this to the January 2026 milestone Jan 27, 2026
@karthiknadig karthiknadig enabled auto-merge (squash) January 27, 2026 19:42
@karthiknadig
Copy link
Member Author

Copy link
Collaborator

@justschen justschen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

@karthiknadig karthiknadig merged commit c7f64eb into main Jan 27, 2026
22 checks passed
@karthiknadig karthiknadig deleted the narrow-angelfish branch January 27, 2026 21:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants