Skip to content

Commit 6df916d

Browse files
committed
Update
1 parent 388d8bf commit 6df916d

10 files changed

Lines changed: 152 additions & 63 deletions

File tree

src/vs/platform/native/common/native.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ export interface ICommonNativeHostService {
129129
openWindow(options?: IOpenEmptyWindowOptions): Promise<void>;
130130
openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise<void>;
131131

132-
openAgentsWindow(): Promise<void>;
132+
openAgentsWindow(options?: { readonly forceNewWindow?: boolean }): Promise<void>;
133133

134134
isFullScreen(options?: INativeHostOptions): Promise<boolean>;
135135
toggleFullScreen(options?: INativeHostOptions): Promise<void>;

src/vs/platform/native/electron-main/nativeHostMainService.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,11 +304,12 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
304304
}, options);
305305
}
306306

307-
async openAgentsWindow(windowId: number | undefined): Promise<void> {
307+
async openAgentsWindow(windowId: number | undefined, options?: { readonly forceNewWindow?: boolean }): Promise<void> {
308308
await this.windowsMainService.openAgentsWindow({
309309
context: OpenContext.API,
310310
contextWindowId: windowId,
311-
cli: this.environmentMainService.args
311+
cli: this.environmentMainService.args,
312+
forceNewWindow: options?.forceNewWindow,
312313
});
313314
}
314315

src/vs/platform/windows/electron-main/windowsMainService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
320320
context: openConfig.context,
321321
contextWindowId: openConfig.contextWindowId,
322322
initialStartup: openConfig.initialStartup,
323+
forceNewWindow: openConfig.forceNewWindow,
323324
};
324325
}
325326

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { $, addDisposableListener } from '../../../../../base/browser/dom.js';
7+
import { DisposableStore } from '../../../../../base/common/lifecycle.js';
8+
import { localize } from '../../../../../nls.js';
9+
import { ICommandService, CommandsRegistry } from '../../../../../platform/commands/common/commands.js';
10+
import { IProductService } from '../../../../../platform/product/common/productService.js';
11+
import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js';
12+
13+
const OPEN_AGENTS_WINDOW_COMMAND = 'workbench.action.openAgentsWindow';
14+
15+
type AgentsBannerClickedEvent = {
16+
source: string;
17+
action: string;
18+
};
19+
20+
type AgentsBannerClickedClassification = {
21+
source: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Where the banner was clicked from.' };
22+
action: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The action taken on the banner.' };
23+
owner: 'benibenj';
24+
comment: 'Tracks clicks on the agents app banner across welcome pages.';
25+
};
26+
27+
export interface IAgentsBannerResult {
28+
readonly element: HTMLElement;
29+
readonly disposables: DisposableStore;
30+
}
31+
32+
/**
33+
* Returns whether the agents banner can be shown.
34+
* The banner requires the `workbench.action.openAgentsWindow` command
35+
* to be registered (desktop builds only) and is limited to Insiders quality.
36+
*/
37+
export function canShowAgentsBanner(productService: IProductService): boolean {
38+
return productService.quality !== 'stable'
39+
&& !!CommandsRegistry.getCommand(OPEN_AGENTS_WINDOW_COMMAND);
40+
}
41+
42+
/**
43+
* Creates a banner that promotes the Agents app.
44+
* The banner contains a button that opens the Agents window.
45+
*
46+
* @param cssClass Dot-separated CSS classes for the banner container (e.g. 'my-banner' or 'foo.bar').
47+
* @param source Identifies where the banner is displayed (e.g. 'welcomePage', 'agentSessionsWelcome').
48+
* @param commandService Used to execute the open command.
49+
* @param telemetryService Used to log banner interactions.
50+
* @param onButtonClick Optional callback invoked when the banner button is clicked.
51+
*/
52+
export function createAgentsBanner(
53+
cssClass: string,
54+
source: string,
55+
commandService: ICommandService,
56+
telemetryService: ITelemetryService,
57+
onButtonClick?: () => void,
58+
): IAgentsBannerResult {
59+
const disposables = new DisposableStore();
60+
61+
const button = $('button.agents-banner-button', {
62+
title: localize('agentsBanner.tryAgentsApp', "Try out the new Agents app"),
63+
},
64+
$('.codicon.codicon-agent.icon-widget'),
65+
$('span.category-title', {}, localize('agentsBanner.tryAgentsAppLabel', "Try out the new Agents app")),
66+
);
67+
disposables.add(addDisposableListener(button, 'click', () => {
68+
onButtonClick?.();
69+
telemetryService.publicLog2<AgentsBannerClickedEvent, AgentsBannerClickedClassification>('agentsBanner.clicked', { source, action: 'openAgentsWindow' });
70+
commandService.executeCommand(OPEN_AGENTS_WINDOW_COMMAND, { forceNewWindow: true });
71+
}));
72+
73+
const element = $(`.${cssClass}`, {}, button);
74+
75+
return { element, disposables };
76+
}

src/vs/workbench/contrib/chat/electron-browser/agentSessions/agentSessionsActions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export class OpenAgentsWindowAction extends Action2 {
3434
});
3535
}
3636

37-
async run(accessor: ServicesAccessor) {
37+
async run(accessor: ServicesAccessor, options?: { forceNewWindow?: boolean }) {
3838
const openerService = accessor.get(IOpenerService);
3939
const productService = accessor.get(IProductService);
4040
const environmentService = accessor.get(IWorkbenchEnvironmentService);
@@ -43,7 +43,7 @@ export class OpenAgentsWindowAction extends Action2 {
4343
await openerService.open(URI.from({ scheme: productService.embedded.urlProtocol, authority: Schemas.file }), { openExternal: true });
4444
} else {
4545
const nativeHostService = accessor.get(INativeHostService);
46-
await nativeHostService.openAgentsWindow();
46+
await nativeHostService.openAgentsWindow({ forceNewWindow: options?.forceNewWindow });
4747
}
4848
}
4949
}

src/vs/workbench/contrib/welcomeAgentSessions/browser/agentSessionsWelcome.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import { IWorkspaceTrustManagementService } from '../../../../platform/workspace
6060
import { IViewDescriptorService, ViewContainerLocation } from '../../../common/views.js';
6161
import { toErrorMessage } from '../../../../base/common/errorMessage.js';
6262
import { ILogService } from '../../../../platform/log/common/log.js';
63+
import { canShowAgentsBanner, createAgentsBanner } from '../../chat/browser/agentSessions/agentSessionsBanner.js';
6364

6465
const configurationKey = 'workbench.startupEditor';
6566
const MAX_SESSIONS = 6;
@@ -593,13 +594,18 @@ export class AgentSessionsWelcomePage extends EditorPane {
593594
this.layoutSessionsControl();
594595
}));
595596

596-
// "View all sessions" link
597-
const openButton = append(container, $('button.agentSessionsWelcome-openSessionsButton'));
598-
openButton.textContent = localize('viewAllSessions', "View All Sessions");
599-
openButton.onclick = () => {
600-
this._closedBy = 'viewAllSessions';
601-
this.revealMaximizedChat();
602-
};
597+
// "Try out the new Agents app" banner
598+
if (canShowAgentsBanner(this.productService)) {
599+
const agentsBanner = createAgentsBanner(
600+
'agentSessionsWelcome-agentsBanner',
601+
'agentSessionsWelcome',
602+
this.commandService,
603+
this.telemetryService,
604+
() => { this._closedBy = 'viewAllSessions'; },
605+
);
606+
this.sessionsControlDisposables.add(agentsBanner.disposables);
607+
append(container, agentsBanner.element);
608+
}
603609
}
604610

605611
private buildWalkthroughs(container: HTMLElement): void {

src/vs/workbench/contrib/welcomeAgentSessions/browser/media/agentSessionsWelcome.css

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -210,25 +210,49 @@
210210
display: none !important;
211211
}
212212

213-
.agentSessionsWelcome-openSessionsButton {
213+
.agentSessionsWelcome-agentsBanner {
214214
display: flex;
215215
align-items: center;
216216
justify-content: center;
217-
gap: 6px;
217+
gap: 8px;
218218
width: 100%;
219-
padding: 8px 16px;
220219
margin-top: 12px;
220+
font-size: 13px;
221+
}
222+
223+
.agentSessionsWelcome-agentsBanner .agents-banner-button {
224+
display: flex;
225+
align-items: center;
226+
padding: 10px;
221227
border: none;
222-
border-radius: 4px;
228+
border-radius: 6px;
223229
background-color: var(--vscode-toolbar-hoverBackground);
224230
color: var(--vscode-foreground);
225231
font-size: 13px;
226232
cursor: pointer;
233+
font-family: inherit;
234+
border-radius: 50px;
235+
width: 100%;
236+
justify-content: center;
227237
}
228238

229-
.agentSessionsWelcome-openSessionsButton:hover {
239+
.agentSessionsWelcome-agentsBanner .codicon {
240+
color: var(--vscode-textLink-foreground) !important;
241+
}
242+
243+
.agentSessionsWelcome-agentsBanner .agents-banner-button:hover {
230244
background-color: var(--vscode-toolbar-activeBackground);
231-
color: var(--vscode-textLink-foreground);
245+
}
246+
247+
.agentSessionsWelcome-agentsBanner .icon-widget {
248+
font-size: 20px;
249+
padding-right: 8px;
250+
}
251+
252+
.agentSessionsWelcome-agentsBanner .category-title {
253+
font-size: 13px;
254+
font-weight: normal;
255+
margin: 0;
232256
}
233257

234258
/* Walkthroughs section */

src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ import { IExtensionService } from '../../../services/extensions/common/extension
6969
import { IHostService } from '../../../services/host/browser/host.js';
7070
import { IWorkbenchThemeService } from '../../../services/themes/common/workbenchThemeService.js';
7171
import { GettingStartedIndexList } from './gettingStartedList.js';
72+
import { canShowAgentsBanner, createAgentsBanner } from '../../chat/browser/agentSessions/agentSessionsBanner.js';
7273
import { AccessibilityVerbositySettingId } from '../../accessibility/browser/accessibilityConfiguration.js';
7374
import { AccessibleViewAction } from '../../accessibility/browser/accessibleViewActions.js';
7475
import { KeybindingLabel } from '../../../../base/browser/ui/keybindingLabel/keybindingLabel.js';
@@ -491,10 +492,6 @@ export class GettingStartedPage extends EditorPane {
491492
}
492493
break;
493494
}
494-
case 'openAgentsWindow': {
495-
this.commandService.executeCommand('workbench.action.openAgentsWindow');
496-
break;
497-
}
498495
case 'openLink': {
499496
this.openerService.open(argument);
500497
break;
@@ -935,31 +932,23 @@ export class GettingStartedPage extends EditorPane {
935932
const recentList = this.buildRecentlyOpenedList();
936933
const gettingStartedList = this.buildGettingStartedWalkthroughsList();
937934

938-
const learnMoreLink = $('a.learn-more-link', {}, localize('welcomePage.learnMore', "Learn more"));
939-
this.categoriesSlideDisposables.add(addDisposableListener(learnMoreLink, 'click', (e) => {
940-
e.stopPropagation();
941-
e.preventDefault();
942-
this.telemetryService.publicLog2<GettingStartedActionEvent, GettingStartedActionClassification>('gettingStarted.ActionExecuted', { command: 'openAgentsLearnMore', argument: undefined, walkthroughId: this.currentWalkthrough?.id });
943-
this.openerService.open('https://code.visualstudio.com');
944-
}));
945-
946-
const agentsBannerButton = $('button.getting-started-category.agents-banner', {
947-
'x-dispatch': 'openAgentsWindow',
948-
title: localize('welcomePage.tryAgentsApp', "Try out the new Agents app"),
949-
},
950-
$('.main-content', {},
951-
$('.codicon.codicon-agent.icon-widget'),
952-
$('h3.category-title.max-lines-3', {}, localize('welcomePage.tryAgentsAppLabel', "Try out the new Agents app")),
953-
learnMoreLink,
954-
),
955-
);
935+
const footerChildren: HTMLElement[] = [];
936+
if (canShowAgentsBanner(this.productService)) {
937+
const agentsBanner = createAgentsBanner(
938+
'getting-started-category.agents-banner',
939+
'welcomePage',
940+
this.commandService,
941+
this.telemetryService,
942+
);
943+
this.categoriesSlideDisposables.add(agentsBanner.disposables);
944+
footerChildren.push(agentsBanner.element);
945+
}
946+
footerChildren.push($('p.showOnStartup', {},
947+
showOnStartupCheckbox.domNode,
948+
showOnStartupLabel,
949+
));
956950

957-
const footer = $('.footer', {},
958-
agentsBannerButton,
959-
$('p.showOnStartup', {},
960-
showOnStartupCheckbox.domNode,
961-
showOnStartupLabel,
962-
));
951+
const footer = $('.footer', {}, ...footerChildren);
963952

964953
const layoutLists = () => {
965954
if (gettingStartedList.itemCount) {

src/vs/workbench/contrib/welcomeGettingStarted/browser/media/gettingStarted.css

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -917,30 +917,22 @@
917917
}
918918

919919
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .footer > .agents-banner {
920-
padding: 8px 10px;
921-
margin-bottom: 30px;
922-
border-radius: 50px;
923920
display: flex;
924921
align-items: center;
925922
justify-content: center;
926-
width: auto;
923+
gap: 8px;
924+
margin-bottom: 12px;
927925
}
928926

929-
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .footer > .agents-banner .main-content {
927+
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .footer > .agents-banner .agents-banner-button {
930928
display: flex;
931929
align-items: center;
932-
justify-content: center;
933-
}
934-
935-
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .footer > .agents-banner .learn-more-link {
936-
margin-left: 10px;
937-
color: var(--vscode-textLink-foreground);
930+
padding: 8px 10px;
931+
border-radius: 50px;
938932
cursor: pointer;
939-
text-decoration: var(--text-link-decoration);
940-
}
941-
942-
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer > .footer > .agents-banner .learn-more-link:hover {
943-
color: var(--vscode-textLink-activeForeground);
933+
font-family: inherit;
934+
font-size: 13px;
935+
margin-bottom: 10px;
944936
}
945937

946938
.monaco-workbench .part.editor > .content .gettingStartedContainer .gettingStartedSlideCategories > .gettingStartedCategoriesContainer .index-list.start-container {

src/vs/workbench/test/electron-browser/workbenchTestServices.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ export class TestNativeHostService implements INativeHostService {
103103
throw new Error('Method not implemented.');
104104
}
105105

106-
async openAgentsWindow(): Promise<void> { }
106+
async openAgentsWindow(_options?: { readonly forceNewWindow?: boolean }): Promise<void> { }
107107

108108
async toggleFullScreen(): Promise<void> { }
109109
async isMaximized(): Promise<boolean> { return true; }

0 commit comments

Comments
 (0)