Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion src/vs/platform/actionWidget/browser/actionList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export interface IActionListItemHover {
/**
* Content to display in the hover. Can be a markdown string or an HTMLElement for full DOM control.
*/
readonly content?: string | MarkdownString | HTMLElement;
readonly content?: string | IMarkdownString | HTMLElement;
/**
* Optional disposable associated with the hover content (e.g. from rendered markdown).
*/
Expand Down
9 changes: 9 additions & 0 deletions src/vs/platform/actionWidget/browser/actionWidget.css
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,15 @@
font-size: 12px;
}

.action-widget .monaco-list .monaco-list-row .description a {
color: var(--vscode-textLink-foreground);
}

.action-widget .monaco-list .monaco-list-row .description a:hover,
.action-widget .monaco-list .monaco-list-row .description a:active {
color: var(--vscode-textLink-activeForeground);
}

.action-widget .monaco-list-row.action .group-title {
color: var(--vscode-descriptionForeground);
margin-left: 0.5em;
Expand Down
3 changes: 2 additions & 1 deletion src/vs/platform/actionWidget/browser/actionWidgetDropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { BaseDropdown, IActionProvider, IBaseDropdownOptions } from '../../../ba
import { IListAccessibilityProvider } from '../../../base/browser/ui/list/listWidget.js';
import { IAction } from '../../../base/common/actions.js';
import { Codicon } from '../../../base/common/codicons.js';
import { IMarkdownString } from '../../../base/common/htmlContent.js';
import { ResolvedKeybinding } from '../../../base/common/keybindings.js';
import { ThemeIcon } from '../../../base/common/themables.js';
import { IKeybindingService } from '../../keybinding/common/keybinding.js';
Expand All @@ -18,7 +19,7 @@ import { IActionWidgetService } from './actionWidget.js';
export interface IActionWidgetDropdownAction extends IAction {
category?: { label: string; order: number; showHeader?: boolean };
icon?: ThemeIcon;
description?: string;
description?: string | IMarkdownString;
/**
* Optional detail text displayed as a second line below the label.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { IKeybindingService } from '../../../../../../platform/keybinding/common
import { IOpenerService } from '../../../../../../platform/opener/common/opener.js';
import { ITelemetryService } from '../../../../../../platform/telemetry/common/telemetry.js';
import { IsSessionsWindowContext } from '../../../../../common/contextkeys.js';
import { IChatEntitlementService } from '../../../../../services/chat/common/chatEntitlementService.js';
import { IChatSessionsService } from '../../../common/chatSessionsService.js';
import { ACTION_ID_NEW_CHAT } from '../../actions/chatActions.js';
import { AgentSessionProviders, AgentSessionTarget, getAgentCanContinueIn, getAgentSessionProvider, isFirstPartyAgentSessionProvider } from '../../agentSessions/agentSessions.js';
Expand Down Expand Up @@ -46,10 +47,11 @@ export class DelegationSessionPickerActionItem extends SessionTypePickerActionIt
@ICommandService commandService: ICommandService,
@IOpenerService openerService: IOpenerService,
@ITelemetryService telemetryService: ITelemetryService,
@IChatEntitlementService chatEntitlementService: IChatEntitlementService,
@IConfigurationService configurationService: IConfigurationService,
@IGitService private readonly gitService: IGitService,
) {
super(action, chatSessionPosition, delegate, pickerOptions, actionWidgetService, keybindingService, contextKeyService, chatSessionsService, commandService, openerService, telemetryService, configurationService);
super(action, chatSessionPosition, delegate, pickerOptions, actionWidgetService, keybindingService, contextKeyService, chatSessionsService, commandService, openerService, telemetryService, chatEntitlementService, configurationService);
this._isSessionsWindow = IsSessionsWindowContext.getValue(contextKeyService) === true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as dom from '../../../../../../base/browser/dom.js';
import { renderLabelWithIcons } from '../../../../../../base/browser/ui/iconLabel/iconLabels.js';
import { IAction } from '../../../../../../base/common/actions.js';
import { Codicon } from '../../../../../../base/common/codicons.js';
import { IMarkdownString, MarkdownString } from '../../../../../../base/common/htmlContent.js';
import { IDisposable } from '../../../../../../base/common/lifecycle.js';
import { ThemeIcon } from '../../../../../../base/common/themables.js';
import { URI } from '../../../../../../base/common/uri.js';
Expand All @@ -20,6 +21,7 @@ import { IContextKeyService } from '../../../../../../platform/contextkey/common
import { IKeybindingService } from '../../../../../../platform/keybinding/common/keybinding.js';
import { IOpenerService } from '../../../../../../platform/opener/common/opener.js';
import { ITelemetryService } from '../../../../../../platform/telemetry/common/telemetry.js';
import { ChatEntitlement, IChatEntitlementService } from '../../../../../services/chat/common/chatEntitlementService.js';
import { IChatSessionsService } from '../../../common/chatSessionsService.js';
import { AgentSessionProviders, AgentSessionTarget, getAgentSessionProvider, getAgentSessionProviderDescription, getAgentSessionProviderIcon, getAgentSessionProviderName, isFirstPartyAgentSessionProvider } from '../../agentSessions/agentSessions.js';
import { ChatConfiguration, getDefaultNewChatSessionType } from '../../../common/constants.js';
Expand Down Expand Up @@ -57,6 +59,7 @@ export class SessionTypePickerActionItem extends ChatInputPickerActionViewItem {
@ICommandService protected readonly commandService: ICommandService,
@IOpenerService protected readonly openerService: IOpenerService,
@ITelemetryService telemetryService: ITelemetryService,
@IChatEntitlementService protected readonly chatEntitlementService: IChatEntitlementService,
@IConfigurationService protected readonly configurationService: IConfigurationService,
) {

Expand All @@ -70,17 +73,18 @@ export class SessionTypePickerActionItem extends ChatInputPickerActionViewItem {
continue;
}

const lockedForEntitlement = this._isLockedForEntitlement(sessionTypeItem.type);
actions.push({
...action,
id: sessionTypeItem.commandId,
label: sessionTypeItem.label,
checked: currentType === sessionTypeItem.type,
icon: this._getSessionIcon(sessionTypeItem),
enabled: this._isSessionTypeEnabled(sessionTypeItem.type),
enabled: lockedForEntitlement ? false : this._isSessionTypeEnabled(sessionTypeItem.type),
category: this._getSessionCategory(sessionTypeItem),
description: this._getSessionDescription(sessionTypeItem),
description: lockedForEntitlement ? this._getUpgradeDescription() : this._getSessionDescription(sessionTypeItem),
tooltip: '',
hover: { content: sessionTypeItem.hoverDescription },
hover: { content: lockedForEntitlement ? this._getUpgradeHover() : sessionTypeItem.hoverDescription },
run: async () => {
Comment on lines +76 to 88
this._run(sessionTypeItem);
},
Expand Down Expand Up @@ -232,6 +236,33 @@ export class SessionTypePickerActionItem extends ChatInputPickerActionViewItem {
return !!this.chatSessionsService.getChatSessionContribution(type);
}

/**
* Whether the given session type is locked behind a plan upgrade for the
* current user's entitlement. The cloud agent is not available to Copilot
* Free or Copilot Student (EDU) users, so it is shown greyed out with an
* Upgrade prompt instead of being selectable.
*/
protected _isLockedForEntitlement(type: AgentSessionTarget): boolean {
if (type !== AgentSessionProviders.Cloud) {
return false;
}
const entitlement = this.chatEntitlementService.entitlement;
return entitlement === ChatEntitlement.Free || entitlement === ChatEntitlement.EDU;
}

private _getUpgradeDescription(): IMarkdownString {
return new MarkdownString(
localize('chat.sessionTarget.upgradeLink', "[Upgrade](command:workbench.action.chat.upgradePlan)"),
{ isTrusted: { enabledCommands: ['workbench.action.chat.upgradePlan'] } }
);
}

private _getUpgradeHover(): MarkdownString {
const hover = new MarkdownString('', { isTrusted: { enabledCommands: ['workbench.action.chat.upgradePlan'] }, supportThemeIcons: true });
hover.appendMarkdown(localize('chat.sessionTarget.upgradeHover', "[Upgrade to GitHub Copilot Pro](command:workbench.action.chat.upgradePlan) to delegate work to the cloud agent."));
return hover;
Comment thread
cwebster-99 marked this conversation as resolved.
}

protected _getSessionCategory(sessionTypeItem: ISessionTypeItem) {
// TODO: Remove hardcoded providers from core
const knownType = getAgentSessionProvider(sessionTypeItem.type);
Expand Down
Loading