Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/vs/sessions/contrib/chat/browser/media/chatInput.css
Original file line number Diff line number Diff line change
Expand Up @@ -251,16 +251,18 @@
.sessions-chat-config-toolbar .monaco-action-bar .action-item.compact-picker {
box-sizing: border-box;
width: 22px;
height: 22px;
min-width: 22px;
padding: 0;
}

.sessions-chat-config-toolbar .monaco-action-bar .action-item.compact-picker .action-label {
box-sizing: border-box;
width: 22px;
height: 22px;
min-width: 22px;
padding: 2px 2px 2px 8px;
justify-content: flex-start;
padding: 0;
justify-content: center;
}

.sessions-chat-config-toolbar .monaco-action-bar .action-item.compact-picker .action-label.model-picker-split {
Expand Down
19 changes: 19 additions & 0 deletions src/vs/sessions/contrib/chat/browser/media/chatView.css
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,22 @@
.agent-sessions-workbench .interactive-session .compact-picker .sessions-chat-dropdown-label {
display: none;
}

.agent-sessions-workbench .interactive-session .compact-picker .sessions-chat-picker-slot,
.agent-sessions-workbench .interactive-session .sessions-chat-picker-slot.compact-picker,
.agent-sessions-workbench .interactive-session .compact-picker .sessions-chat-picker-slot .action-label,
.agent-sessions-workbench .interactive-session .sessions-chat-picker-slot.compact-picker .action-label {
box-sizing: border-box;
width: 22px;
height: 22px;
min-width: 22px;
padding: 0;
justify-content: center;
}

.agent-sessions-workbench .interactive-session .compact-picker .sessions-chat-picker-slot .action-label > .codicon,
.agent-sessions-workbench .interactive-session .sessions-chat-picker-slot.compact-picker .action-label > .codicon {
width: var(--vscode-codiconFontSize-compact);
height: var(--vscode-codiconFontSize-compact);
line-height: var(--vscode-codiconFontSize-compact);
}
35 changes: 24 additions & 11 deletions src/vs/sessions/contrib/chat/browser/media/chatWidget.css
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@
align-self: center;
}

/* Flex centering shares attachment growth above and below the midpoint. Offset
* that growth so the bottom controls stay anchored and the composer grows up. */
.sessions-chat-widget:not(.new-chat-in-session) > .new-chat-widget-container > .new-chat-widget-content {
position: relative;
}

.new-chat-widget-container .new-chat-bottom-container {
width: 100%;
max-width: 800px;
Expand Down Expand Up @@ -164,6 +170,7 @@
.agent-sessions-workbench:not(.phone-layout) .new-chat-widget-container .new-chat-bottom-container .compact-picker.sessions-chat-picker-slot {
box-sizing: border-box;
width: 22px;
height: 22px;
min-width: 22px;
padding: 0;
}
Expand All @@ -172,9 +179,10 @@
.agent-sessions-workbench:not(.phone-layout) .new-chat-widget-container .new-chat-bottom-container .compact-picker.sessions-chat-picker-slot .action-label {
box-sizing: border-box;
width: 22px;
height: 22px;
min-width: 22px;
justify-content: flex-start;
padding: 2px 2px 2px 8px;
justify-content: center;
padding: 0;
}

.agent-sessions-workbench:not(.phone-layout) .new-chat-widget-container .new-chat-bottom-container .compact-picker.sessions-chat-picker-slot .action-label > .codicon {
Expand Down Expand Up @@ -220,20 +228,25 @@
display: none;
}

/* Icon-only action items in the bottom row (e.g. OpenTelemetry status pill)
* lack the chevron that visually balances the 7px left padding, so use
* symmetric horizontal padding and drop the picker min-width that would
* otherwise leave the icon left-aligned inside a 30px box. */
.new-chat-widget-container .new-chat-bottom-container .new-chat-status-toolbar .monaco-action-bar .action-item,
.new-chat-widget-container .new-chat-bottom-container .new-chat-status-toolbar .monaco-action-bar .action-item .action-label {
min-width: 0;
/* Icon status actions use the compact control box; text actions remain intrinsic. */
.agent-sessions-workbench:not(.phone-layout) .new-chat-widget-container .new-chat-bottom-container .new-chat-status-toolbar .monaco-action-bar .action-item.new-chat-status-icon-action {
width: 22px;
min-width: 22px;
}

.new-chat-widget-container .new-chat-bottom-container .new-chat-status-toolbar .action-label {
padding: 3px 4px;
.agent-sessions-workbench:not(.phone-layout) .new-chat-widget-container .new-chat-bottom-container .new-chat-status-toolbar .new-chat-status-icon-action .action-label {
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
min-width: 22px;
padding: 0;
}

.agent-sessions-workbench:not(.phone-layout) .new-chat-widget-container .new-chat-bottom-container .new-chat-status-toolbar .new-chat-status-icon-action .action-label.codicon {
font-size: var(--vscode-codiconFontSize-compact);
}

/* The category row is quiet at rest, while hover/open state reveals the active target. */
Expand Down
61 changes: 58 additions & 3 deletions src/vs/sessions/contrib/chat/browser/newChatInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ import { IChatInputNoticeHubService } from '../../../../workbench/contrib/chat/b
import { ChatInputPickerResponsiveLayout, IChatInputPickerResponsiveLayoutItem } from '../../../../workbench/contrib/chat/browser/widget/input/chatInputPickerResponsiveLayout.js';
import { chatInputStackClass, chatInputStackSlotClass, ChatInputStackSlot, refreshChatInputStack, setChatInputStackInputFocused, setChatInputStackSlot } from '../../../../workbench/contrib/chat/browser/widget/input/chatInputStack.js';
import { IChatSubmitRequestHandlerService } from '../../../../workbench/contrib/chat/browser/chatSubmitRequestHandlerService.js';
import { isPhoneLayout } from '../../../browser/parts/mobile/mobileLayout.js';
import { INewChatModelPickerService, NewChatModelPickerService } from './newChatModelPicker.js';
import { ModelPicker, ModelPickerActionViewItem } from './modelPicker.js';
import { ISessionModelSelection, SessionModelSelection } from './sessionModelSelection.js';
Expand All @@ -106,6 +107,7 @@ import { ISessionContext, SessionContext } from '../../../services/sessions/brow
import { AGENT_SESSIONS_SCOPED_INPUT_HISTORY_SETTING } from './sessionsChatHistory.js';
import { IChatStatusItemService } from '../../../../workbench/contrib/chat/browser/chatStatus/chatStatusItemService.js';
import { handleTerminalCommandPaste, isTerminalCommandInput } from '../../../../workbench/contrib/chat/browser/chatTerminalCommandPaste.js';
import { compactCodiconsIn } from '../../../../workbench/contrib/chat/browser/chatIcons.js';
import { IChatPasteTargetService } from '../../../../workbench/contrib/chat/browser/chat.js';
import { ChatDynamicVariableModel } from '../../../../workbench/contrib/chat/browser/attachments/chatDynamicVariables.js';
import { NewChatInputPasteTarget } from './newChatInputPasteTarget.js';
Expand Down Expand Up @@ -220,6 +222,8 @@ export function hasSendableNewChatContent(query: string, attachments: readonly I

class NewChatInputStatusActionViewItem extends MenuEntryActionViewItem {
private readonly hoverContentDisposables = this._register(new MutableDisposable<DisposableStore>());
private _container: HTMLElement | undefined;
private _compactCodiconClass: string | undefined;

constructor(
action: MenuItemAction,
Expand All @@ -238,7 +242,9 @@ class NewChatInputStatusActionViewItem extends MenuEntryActionViewItem {
}

override render(container: HTMLElement): void {
this._container = container;
super.render(container);
this._updateIconPresentation();

if (this._commandAction.id !== OTEL_STATUS_COMMAND) {
return;
Expand All @@ -251,6 +257,34 @@ class NewChatInputStatusActionViewItem extends MenuEntryActionViewItem {
}));
}

protected override updateClass(): void {
if (this._compactCodiconClass) {
this.label?.classList.remove(this._compactCodiconClass);
this._compactCodiconClass = undefined;
}
super.updateClass();
this._updateIconPresentation();
}

private _updateIconPresentation(): void {
const rendersIcon = !!this.label && (this.label.classList.contains('codicon') || this.label.classList.contains('icon'));
this._container?.classList.toggle('new-chat-status-icon-action', rendersIcon);
if (rendersIcon && this._container && this.label?.classList.contains('codicon')) {
const originalCodiconClass = this._getCodiconClass();
compactCodiconsIn(this._container);
const compactCodiconClass = this._getCodiconClass();
if (compactCodiconClass !== originalCodiconClass) {
this._compactCodiconClass = compactCodiconClass;
}
}
}

private _getCodiconClass(): string | undefined {
return this.label
? [...this.label.classList].find(className => className.startsWith('codicon-') && !className.startsWith('codicon-modifier-'))
: undefined;
}

override async onClick(event: MouseEvent): Promise<void> {
if (this._commandAction.id === OTEL_STATUS_COMMAND && this.element) {
event.preventDefault();
Expand Down Expand Up @@ -444,6 +478,7 @@ export class NewChatInputWidget extends Disposable implements IHistoryNavigation
private readonly _compactModelPicker = observableValue(this, false);
private _primaryPickerResponsiveLayout: ChatInputPickerResponsiveLayout | undefined;
private _secondaryPickerResponsiveLayout: ChatInputPickerResponsiveLayout | undefined;
private _updateAttachmentOffset: (() => void) | undefined;

// Input state
private _draftState: IDraftState | undefined = {
Expand Down Expand Up @@ -668,6 +703,24 @@ export class NewChatInputWidget extends Disposable implements IHistoryNavigation
const attachRow = dom.append(inputArea, dom.$('.sessions-chat-attach-row'));
const attachedContextContainer = dom.append(attachRow, dom.$('.sessions-chat-attached-context'));
this._contextAttachments.renderAttachedContext(attachedContextContainer);
const updateAttachmentOffset = () => {
if (isPhoneLayout(this.layoutService)) {
parent.style.removeProperty('top');
return;
}
parent.style.top = `${-attachRow.getBoundingClientRect().height / 2}px`;
Comment thread
justschen marked this conversation as resolved.
};
this._updateAttachmentOffset = updateAttachmentOffset;
const attachmentResizeObserver = this._register(new dom.DisposableResizeObserver(
'NewChatInputWidget.attachments',
updateAttachmentOffset,
dom.getWindow(attachRow),
));
this._register(attachmentResizeObserver.observe(attachRow));
this._register(toDisposable(() => {
this._updateAttachmentOffset = undefined;
parent.style.removeProperty('top');
}));
this._register(this.instantiationService.createInstance(ChatDragAndDrop, () => undefined, {
get attachments() { return contextAttachments.attachments; },
addAttachments: (entries: readonly IChatRequestVariableEntry[]) => contextAttachments.addAttachments(...entries),
Expand Down Expand Up @@ -737,7 +790,7 @@ export class NewChatInputWidget extends Disposable implements IHistoryNavigation
hiddenItemStrategy: HiddenItemStrategy.NoHide,
toolbarOptions: { primaryGroup: () => true },
actionViewItemProvider: (action, options) => {
if (action.id === OTEL_STATUS_COMMAND && action instanceof MenuItemAction) {
if (action instanceof MenuItemAction) {
return this.instantiationService.createInstance(NewChatInputStatusActionViewItem, action, options);
}
return undefined;
Expand Down Expand Up @@ -1174,13 +1227,14 @@ export class NewChatInputWidget extends Disposable implements IHistoryNavigation
if (!element) {
continue;
}
const isModelPicker = element.classList.contains('model-picker-item');
items.push({
element,
canShrink: configToolbar.getItemAction(index)?.id === 'sessions.modelPicker',
canShrink: isModelPicker,
isCompact: () => element.classList.contains('compact-picker'),
setCompact: (compact: boolean) => {
element.classList.toggle('compact-picker', compact);
if (configToolbar.getItemAction(index)?.id === 'sessions.modelPicker') {
if (isModelPicker) {
this._compactModelPicker.set(compact, undefined);
}
},
Expand Down Expand Up @@ -1617,6 +1671,7 @@ export class NewChatInputWidget extends Disposable implements IHistoryNavigation
}

layout(_height: number, _width: number): void {
this._updateAttachmentOffset?.();
this._editor?.layout();
this._primaryPickerResponsiveLayout?.layout();
this._secondaryPickerResponsiveLayout?.layout();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ export default defineThemedFixtureGroup({ path: 'sessions/chat/input/' }, {
})
}),
ResponsiveModelResizeCycleCompact: defineComponentFixture({
labels: { kind: 'screenshot', blocksCi: true },
expectedVisualDescriptions: ['The Agents active-session chat input shows its compact model codicon centered with equal padding inside a 22-pixel square control while the model configuration remains visible.'],
virtualTime: { enabled: false },
render: context => renderChatInput(sessionsWindowContext(context), {
isSessionsWindow: true,
Expand All @@ -111,6 +113,8 @@ export default defineThemedFixtureGroup({ path: 'sessions/chat/input/' }, {
})
}),
ResponsiveModelResizeCycleMinimal: defineComponentFixture({
labels: { kind: 'screenshot', blocksCi: true },
expectedVisualDescriptions: ['The Agents active-session chat input shows compact model and permission codicons centered with equal padding inside matching 22-pixel square controls, aligned with the expanded toolbar height.'],
virtualTime: { enabled: false },
render: context => renderChatInput(sessionsWindowContext(context), {
isSessionsWindow: true,
Expand Down
Loading
Loading