Skip to content

Commit 4698279

Browse files
authored
Merge pull request microsoft#196671 from microsoft/roblou/other-thrush
Add chat agent header animation
2 parents 4cddd62 + 5ba99f9 commit 4698279

File tree

3 files changed

+38
-5
lines changed

3 files changed

+38
-5
lines changed

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { ICompressibleTreeRenderer } from 'vs/base/browser/ui/tree/objectTree';
1616
import { IAsyncDataSource, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';
1717
import { IAction } from 'vs/base/common/actions';
1818
import { distinct } from 'vs/base/common/arrays';
19-
import { IntervalTimer } from 'vs/base/common/async';
19+
import { IntervalTimer, disposableTimeout } from 'vs/base/common/async';
2020
import { Codicon } from 'vs/base/common/codicons';
2121
import { Emitter, Event } from 'vs/base/common/event';
2222
import { FuzzyScore } from 'vs/base/common/filters';
@@ -70,6 +70,7 @@ interface IChatListItemTemplate {
7070
readonly rowContainer: HTMLElement;
7171
readonly titleToolbar: MenuWorkbenchToolBar;
7272
readonly avatarContainer: HTMLElement;
73+
readonly agentAvatarContainer: HTMLElement;
7374
readonly username: HTMLElement;
7475
readonly detail: HTMLElement;
7576
readonly value: HTMLElement;
@@ -225,6 +226,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
225226
const header = dom.append(rowContainer, $('.header'));
226227
const user = dom.append(header, $('.user'));
227228
const avatarContainer = dom.append(user, $('.avatar-container'));
229+
const agentAvatarContainer = dom.append(user, $('.agent-avatar-container'));
228230
const username = dom.append(user, $('h3.username'));
229231
const detailContainer = dom.append(user, $('span.detail-container'));
230232
const detail = dom.append(detailContainer, $('span.detail'));
@@ -249,7 +251,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
249251
}));
250252

251253

252-
const template: IChatListItemTemplate = { avatarContainer, username, detail, referencesListContainer, value, rowContainer, elementDisposables, titleToolbar, templateDisposables, contextKeyService };
254+
const template: IChatListItemTemplate = { avatarContainer, agentAvatarContainer, username, detail, referencesListContainer, value, rowContainer, elementDisposables, titleToolbar, templateDisposables, contextKeyService };
253255
return template;
254256
}
255257

@@ -361,15 +363,29 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
361363
}
362364

363365
if (isResponseVM(element) && element.agent && !element.agent.metadata.isDefault) {
366+
dom.show(templateData.agentAvatarContainer);
364367
const icon = this.getAgentIcon(element.agent.metadata);
365368
if (icon instanceof URI) {
366369
const avatarIcon = dom.$<HTMLImageElement>('img.icon');
367370
avatarIcon.src = FileAccess.uriToBrowserUri(icon).toString(true);
368-
templateData.avatarContainer.appendChild(dom.$('.avatar', undefined, avatarIcon));
371+
templateData.agentAvatarContainer.replaceChildren(dom.$('.avatar', undefined, avatarIcon));
369372
} else if (icon) {
370373
const avatarIcon = dom.$(ThemeIcon.asCSSSelector(icon));
371-
templateData.avatarContainer.appendChild(dom.$('.avatar.codicon-avatar', undefined, avatarIcon));
374+
templateData.agentAvatarContainer.replaceChildren(dom.$('.avatar.codicon-avatar', undefined, avatarIcon));
372375
}
376+
377+
templateData.agentAvatarContainer.classList.toggle('complete', element.isComplete);
378+
if (!element.agentAvatarHasBeenRendered && !element.isComplete) {
379+
element.agentAvatarHasBeenRendered = true;
380+
templateData.agentAvatarContainer.classList.remove('loading');
381+
templateData.elementDisposables.add(disposableTimeout(() => {
382+
templateData.agentAvatarContainer.classList.toggle('loading', !element.isComplete);
383+
}, 100));
384+
} else {
385+
templateData.agentAvatarContainer.classList.toggle('loading', !element.isComplete);
386+
}
387+
} else {
388+
dom.hide(templateData.agentAvatarContainer);
373389
}
374390
}
375391

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,22 @@
113113
font-size: 14px;
114114
}
115115

116+
.interactive-item-container .header .agent-avatar-container {
117+
margin-left: -30px;
118+
transition: margin 0.15s ease-out;
119+
z-index: -1;
120+
}
121+
122+
.interactive-item-container .header .agent-avatar-container.loading {
123+
margin-left: 0px;
124+
z-index: 1;
125+
}
126+
127+
.interactive-item-container .header .agent-avatar-container.complete {
128+
margin-left: -12px;
129+
z-index: 1;
130+
}
131+
116132
.monaco-list-row:not(.focused) .interactive-item-container:not(:hover) .header .monaco-toolbar,
117133
.monaco-list:not(:focus-within) .monaco-list-row .interactive-item-container:not(:hover) .header .monaco-toolbar,
118134
.monaco-list-row:not(.focused) .interactive-item-container:not(:hover) .header .monaco-toolbar .action-label,

src/vs/workbench/contrib/chat/common/chatViewModel.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export interface IChatResponseViewModel {
100100
readonly errorDetails?: IChatResponseErrorDetails;
101101
readonly contentUpdateTimings?: IChatLiveUpdateData;
102102
renderData?: IChatResponseRenderData;
103+
agentAvatarHasBeenRendered?: boolean;
103104
currentRenderedHeight: number | undefined;
104105
setVote(vote: InteractiveSessionVoteDirection): void;
105106
usedReferencesExpanded?: boolean;
@@ -318,7 +319,7 @@ export class ChatResponseViewModel extends Disposable implements IChatResponseVi
318319
}
319320

320321
renderData: IChatResponseRenderData | undefined = undefined;
321-
322+
agentAvatarHasBeenRendered?: boolean;
322323
currentRenderedHeight: number | undefined;
323324

324325
private _usedReferencesExpanded: boolean | undefined;

0 commit comments

Comments
 (0)