mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 13:46:13 +00:00
Merge pull request #210976 from microsoft/roblou/wonderful-carp
Add button to chat hover and make it disposable
This commit is contained in:
commit
3477776559
|
@ -5,24 +5,38 @@
|
|||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { h } from 'vs/base/browser/dom';
|
||||
import { Button } from 'vs/base/browser/ui/button/button';
|
||||
import { renderIcon } from 'vs/base/browser/ui/iconLabel/iconLabels';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { FileAccess } from 'vs/base/common/network';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { showExtensionsWithIdsCommandId } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { verifiedPublisherIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
|
||||
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
|
||||
export class ChatAgentHover {
|
||||
export class ChatAgentHover extends Disposable {
|
||||
public readonly domNode: HTMLElement;
|
||||
|
||||
private readonly icon: HTMLElement;
|
||||
private readonly name: HTMLElement;
|
||||
private readonly extensionName: HTMLElement;
|
||||
private readonly verifiedBadge: HTMLElement;
|
||||
private readonly publisherName: HTMLElement;
|
||||
private readonly description: HTMLElement;
|
||||
|
||||
private currentAgent: IChatAgentData | undefined;
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
@IChatAgentService private readonly chatAgentService: IChatAgentService,
|
||||
@IExtensionsWorkbenchService private readonly extensionService: IExtensionsWorkbenchService,
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
) {
|
||||
const agent = this.chatAgentService.getAgent(id)!;
|
||||
super();
|
||||
|
||||
const hoverElement = h(
|
||||
'.chat-agent-hover@root',
|
||||
|
@ -38,45 +52,75 @@ export class ChatAgentHover {
|
|||
]),
|
||||
]),
|
||||
]),
|
||||
h('.chat-agent-hover-description@description'),
|
||||
h('span.chat-agent-hover-description@description'),
|
||||
h('span.chat-agent-hover-marketplace-button@button'),
|
||||
]);
|
||||
this.domNode = hoverElement.root;
|
||||
|
||||
this.icon = hoverElement.icon;
|
||||
this.name = hoverElement.name;
|
||||
this.extensionName = hoverElement.extensionName;
|
||||
this.description = hoverElement.description;
|
||||
|
||||
hoverElement.separator.textContent = '|';
|
||||
|
||||
this.verifiedBadge = dom.$('span.extension-verified-publisher', undefined, renderIcon(verifiedPublisherIcon));
|
||||
this.verifiedBadge.style.display = 'none';
|
||||
|
||||
this.publisherName = dom.$('span.chat-agent-hover-publisher-name');
|
||||
dom.append(
|
||||
hoverElement.publisher,
|
||||
this.verifiedBadge,
|
||||
this.publisherName);
|
||||
|
||||
const label = localize('marketplaceLabel', "View in Marketplace") + '.';
|
||||
const marketplaceButton = this._register(new Button(hoverElement.button, {
|
||||
title: label,
|
||||
buttonBackground: undefined,
|
||||
buttonBorder: undefined,
|
||||
buttonForeground: undefined,
|
||||
buttonHoverBackground: undefined,
|
||||
buttonSecondaryBackground: undefined,
|
||||
buttonSecondaryForeground: undefined,
|
||||
buttonSecondaryHoverBackground: undefined,
|
||||
buttonSeparator: undefined,
|
||||
}));
|
||||
marketplaceButton.label = label;
|
||||
this._register(marketplaceButton.onDidClick(() => {
|
||||
if (this.currentAgent) {
|
||||
this.commandService.executeCommand(showExtensionsWithIdsCommandId, [this.currentAgent.extensionId.value]);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
setAgent(id: string): void {
|
||||
const agent = this.chatAgentService.getAgent(id)!;
|
||||
this.currentAgent = agent;
|
||||
|
||||
if (agent.metadata.icon instanceof URI) {
|
||||
const avatarIcon = dom.$<HTMLImageElement>('img.icon');
|
||||
avatarIcon.src = FileAccess.uriToBrowserUri(agent.metadata.icon).toString(true);
|
||||
hoverElement.icon.replaceChildren(dom.$('.avatar', undefined, avatarIcon));
|
||||
this.icon.replaceChildren(dom.$('.avatar', undefined, avatarIcon));
|
||||
} else if (agent.metadata.themeIcon) {
|
||||
const avatarIcon = dom.$(ThemeIcon.asCSSSelector(agent.metadata.themeIcon));
|
||||
hoverElement.icon.replaceChildren(dom.$('.avatar.codicon-avatar', undefined, avatarIcon));
|
||||
this.icon.replaceChildren(dom.$('.avatar.codicon-avatar', undefined, avatarIcon));
|
||||
}
|
||||
|
||||
hoverElement.name.textContent = `@${agent.name}`;
|
||||
hoverElement.extensionName.textContent = agent.extensionDisplayName;
|
||||
hoverElement.separator.textContent = '|';
|
||||
|
||||
const verifiedBadge = dom.$('span.extension-verified-publisher', undefined, renderIcon(verifiedPublisherIcon));
|
||||
verifiedBadge.style.display = 'none';
|
||||
dom.append(
|
||||
hoverElement.publisher,
|
||||
verifiedBadge,
|
||||
agent.extensionPublisher);
|
||||
|
||||
this.name.textContent = `@${agent.name}`;
|
||||
this.extensionName.textContent = agent.extensionDisplayName;
|
||||
this.publisherName.textContent = agent.extensionPublisher;
|
||||
|
||||
const description = agent.description && !agent.description.endsWith('.') ?
|
||||
`${agent.description}. ` :
|
||||
(agent.description || '');
|
||||
hoverElement.description.textContent = description;
|
||||
this.description.textContent = description;
|
||||
|
||||
// const marketplaceLink = document.createElement('a');
|
||||
// marketplaceLink.setAttribute('href', `command:${showExtensionsWithIdsCommandId}?${encodeURIComponent(JSON.stringify([agent.extensionId.value]))}`);
|
||||
// marketplaceLink.textContent = localize('marketplaceLabel', "View in Marketplace") + '.';
|
||||
// hoverElement.description.appendChild(marketplaceLink);
|
||||
|
||||
this.extensionService.getExtensions([{ id: agent.extensionId.value }], CancellationToken.None).then(extensions => {
|
||||
const cancel = this._register(new CancellationTokenSource());
|
||||
this.extensionService.getExtensions([{ id: agent.extensionId.value }], cancel.token).then(extensions => {
|
||||
cancel.dispose();
|
||||
const extension = extensions[0];
|
||||
if (extension?.publisherDomain?.verified) {
|
||||
verifiedBadge.style.display = '';
|
||||
this.verifiedBadge.style.display = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -93,6 +93,7 @@ interface IChatListItemTemplate {
|
|||
readonly contextKeyService: IContextKeyService;
|
||||
readonly templateDisposables: IDisposable;
|
||||
readonly elementDisposables: DisposableStore;
|
||||
readonly agentHover: ChatAgentHover;
|
||||
}
|
||||
|
||||
interface IItemHeightChangeParams {
|
||||
|
@ -293,16 +294,18 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
|||
}));
|
||||
}
|
||||
|
||||
const agentHover = templateDisposables.add(this.instantiationService.createInstance(ChatAgentHover));
|
||||
|
||||
templateDisposables.add(this.hoverService.setupUpdatableHover(getDefaultHoverDelegate('mouse'), header, () => {
|
||||
if (isResponseVM(template.currentElement) && template.currentElement.agent) {
|
||||
const hover = this.instantiationService.createInstance(ChatAgentHover, template.currentElement.agent.id);
|
||||
return hover.domNode;
|
||||
agentHover.setAgent(template.currentElement.agent.id);
|
||||
return agentHover.domNode;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}));
|
||||
|
||||
const template: IChatListItemTemplate = { avatarContainer, agentAvatarContainer, username, detail, referencesListContainer, value, rowContainer, elementDisposables, titleToolbar, templateDisposables, contextKeyService };
|
||||
const template: IChatListItemTemplate = { avatarContainer, agentAvatarContainer, username, detail, referencesListContainer, value, rowContainer, elementDisposables, titleToolbar, templateDisposables, contextKeyService, agentHover };
|
||||
return template;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,8 @@ export class ChatMarkdownDecorationsRenderer {
|
|||
const container = dom.$('span.chat-resource-widget', undefined, dom.$('span', undefined, name));
|
||||
|
||||
store.add(this.hoverService.setupUpdatableHover(getDefaultHoverDelegate('element'), container, () => {
|
||||
const hover = this.instantiationService.createInstance(ChatAgentHover, id);
|
||||
const hover = store.add(this.instantiationService.createInstance(ChatAgentHover));
|
||||
hover.setAgent(id);
|
||||
return hover.domNode;
|
||||
}));
|
||||
return container;
|
||||
|
|
|
@ -14,7 +14,7 @@ import { isEqual } from 'vs/base/common/resources';
|
|||
import { isDefined } from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import 'vs/css!./media/chat';
|
||||
import 'vs/css!./media/chatHover';
|
||||
import 'vs/css!./media/chatAgentHover';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
|
|
|
@ -51,6 +51,14 @@
|
|||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.chat-agent-hover-description {
|
||||
.chat-agent-hover-description,
|
||||
.chat-agent-hover-marketplace-button .monaco-text-button {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.chat-agent-hover .chat-agent-hover-marketplace-button .monaco-text-button {
|
||||
display: unset;
|
||||
padding: unset;
|
||||
border: unset;
|
||||
line-height: unset;
|
||||
}
|
|
@ -2975,7 +2975,8 @@ CommandsRegistry.registerCommand('workbench.extensions.action.showExtensionsForL
|
|||
});
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand('workbench.extensions.action.showExtensionsWithIds', function (accessor: ServicesAccessor, extensionIds: string[]) {
|
||||
export const showExtensionsWithIdsCommandId = 'workbench.extensions.action.showExtensionsWithIds';
|
||||
CommandsRegistry.registerCommand(showExtensionsWithIdsCommandId, function (accessor: ServicesAccessor, extensionIds: string[]) {
|
||||
const paneCompositeService = accessor.get(IPaneCompositePartService);
|
||||
|
||||
return paneCompositeService.openPaneComposite(VIEWLET_ID, ViewContainerLocation.Sidebar, true)
|
||||
|
|
Loading…
Reference in a new issue