Skip to content

Commit 5f1da36

Browse files
authored
1 parent b750bb0 commit 5f1da36

File tree

10 files changed

+104
-32
lines changed

10 files changed

+104
-32
lines changed

src/vs/workbench/common/theme.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -594,9 +594,8 @@ export const STATUS_BAR_OFFLINE_ITEM_HOVER_BACKGROUND = registerColor('statusBar
594594
hcLight: null
595595
}, localize('statusBarOfflineItemHoverBackground', "Status bar item background hover color when the workbench is offline."));
596596

597-
export const EXTENSION_BADGE_REMOTE_BACKGROUND = registerColor('extensionBadge.remoteBackground', ACTIVITY_BAR_BADGE_BACKGROUND, localize('extensionBadge.remoteBackground', "Background color for the remote badge in the extensions view."));
598-
599-
export const EXTENSION_BADGE_REMOTE_FOREGROUND = registerColor('extensionBadge.remoteForeground', ACTIVITY_BAR_BADGE_FOREGROUND, localize('extensionBadge.remoteForeground', "Foreground color for the remote badge in the extensions view."));
597+
export const EXTENSION_BADGE_BACKGROUND = registerColor('extensionBadge.remoteBackground', ACTIVITY_BAR_BADGE_BACKGROUND, localize('extensionBadge.remoteBackground', "Background color for the remote badge in the extensions view."));
598+
export const EXTENSION_BADGE_FOREGROUND = registerColor('extensionBadge.remoteForeground', ACTIVITY_BAR_BADGE_FOREGROUND, localize('extensionBadge.remoteForeground', "Foreground color for the remote badge in the extensions view."));
600599

601600

602601
// < --- Side Bar --- >

src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { ILabelService } from '../../../../platform/label/common/label.js';
1616
import { extensionButtonProminentBackground, ExtensionStatusAction } from './extensionsActions.js';
1717
import { IThemeService, registerThemingParticipant } from '../../../../platform/theme/common/themeService.js';
1818
import { ThemeIcon } from '../../../../base/common/themables.js';
19-
import { EXTENSION_BADGE_REMOTE_BACKGROUND, EXTENSION_BADGE_REMOTE_FOREGROUND } from '../../../common/theme.js';
19+
import { EXTENSION_BADGE_BACKGROUND, EXTENSION_BADGE_FOREGROUND } from '../../../common/theme.js';
2020
import { Emitter, Event } from '../../../../base/common/event.js';
2121
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
2222
import { CountBadge } from '../../../../base/browser/ui/countBadge/countBadge.js';
@@ -478,7 +478,7 @@ export class PreReleaseBookmarkWidget extends ExtensionWidget {
478478

479479
export class RemoteBadgeWidget extends ExtensionWidget {
480480

481-
private readonly remoteBadge = this._register(new MutableDisposable<RemoteBadge>());
481+
private readonly remoteBadge = this._register(new MutableDisposable<ExtensionIconBadge>());
482482

483483
private element: HTMLElement;
484484

@@ -489,7 +489,7 @@ export class RemoteBadgeWidget extends ExtensionWidget {
489489
@IInstantiationService private readonly instantiationService: IInstantiationService
490490
) {
491491
super();
492-
this.element = append(parent, $('.extension-remote-badge-container'));
492+
this.element = append(parent, $(''));
493493
this.render();
494494
this._register(toDisposable(() => this.clear()));
495495
}
@@ -504,38 +504,42 @@ export class RemoteBadgeWidget extends ExtensionWidget {
504504
if (!this.extension || !this.extension.local || !this.extension.server || !(this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) || this.extension.server !== this.extensionManagementServerService.remoteExtensionManagementServer) {
505505
return;
506506
}
507-
this.remoteBadge.value = this.instantiationService.createInstance(RemoteBadge, this.tooltip);
507+
let tooltip: string | undefined;
508+
if (this.tooltip && this.extensionManagementServerService.remoteExtensionManagementServer) {
509+
tooltip = localize('remote extension title', "Extension in {0}", this.extensionManagementServerService.remoteExtensionManagementServer.label);
510+
}
511+
this.remoteBadge.value = this.instantiationService.createInstance(ExtensionIconBadge, remoteIcon, tooltip);
508512
append(this.element, this.remoteBadge.value.element);
509513
}
510514
}
511515

512-
class RemoteBadge extends Disposable {
516+
export class ExtensionIconBadge extends Disposable {
513517

514518
readonly element: HTMLElement;
515519
readonly elementHover: IManagedHover;
516520

517521
constructor(
518-
private readonly tooltip: boolean,
522+
private readonly icon: ThemeIcon,
523+
private readonly tooltip: string | undefined,
519524
@IHoverService hoverService: IHoverService,
520525
@ILabelService private readonly labelService: ILabelService,
521526
@IThemeService private readonly themeService: IThemeService,
522-
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
523527
) {
524528
super();
525-
this.element = $('div.extension-badge.extension-remote-badge');
529+
this.element = $('div.extension-badge.extension-icon-badge');
526530
this.elementHover = this._register(hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), this.element, ''));
527531
this.render();
528532
}
529533

530534
private render(): void {
531-
append(this.element, $('span' + ThemeIcon.asCSSSelector(remoteIcon)));
535+
append(this.element, $('span' + ThemeIcon.asCSSSelector(this.icon)));
532536

533537
const applyBadgeStyle = () => {
534538
if (!this.element) {
535539
return;
536540
}
537-
const bgColor = this.themeService.getColorTheme().getColor(EXTENSION_BADGE_REMOTE_BACKGROUND);
538-
const fgColor = this.themeService.getColorTheme().getColor(EXTENSION_BADGE_REMOTE_FOREGROUND);
541+
const bgColor = this.themeService.getColorTheme().getColor(EXTENSION_BADGE_BACKGROUND);
542+
const fgColor = this.themeService.getColorTheme().getColor(EXTENSION_BADGE_FOREGROUND);
539543
this.element.style.backgroundColor = bgColor ? bgColor.toString() : '';
540544
this.element.style.color = fgColor ? fgColor.toString() : '';
541545
};
@@ -544,8 +548,8 @@ class RemoteBadge extends Disposable {
544548

545549
if (this.tooltip) {
546550
const updateTitle = () => {
547-
if (this.element && this.extensionManagementServerService.remoteExtensionManagementServer) {
548-
this.elementHover.update(localize('remote extension title', "Extension in {0}", this.extensionManagementServerService.remoteExtensionManagementServer.label));
551+
if (this.element) {
552+
this.elementHover.update(this.tooltip);
549553
}
550554
};
551555
this._register(this.labelService.onDidChangeFormatters(() => updateTitle()));

src/vs/workbench/contrib/extensions/browser/media/extension.css

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
bottom: 5px;
3232
}
3333

34-
.extension-list-item > .icon-container .extension-badge.extension-remote-badge {
34+
.extension-list-item > .icon-container .extension-badge.extension-icon-badge {
3535
width: 22px;
3636
height: 22px;
3737
line-height: 22px;
@@ -42,7 +42,7 @@
4242
justify-content: center;
4343
}
4444

45-
.extension-list-item > .icon-container .extension-remote-badge .codicon {
45+
.extension-list-item > .icon-container .extension-icon-badge .codicon {
4646
color: currentColor;
4747
}
4848

@@ -120,11 +120,11 @@
120120
text-align: right;
121121
}
122122

123-
.extension-list-item > .details > .header-container > .header .extension-remote-badge .codicon {
123+
.extension-list-item > .details > .header-container > .header .extension-icon-badge .codicon {
124124
margin-right: 0;
125125
}
126126

127-
.extension-list-item > .details > .header-container > .header .extension-remote-badge {
127+
.extension-list-item > .details > .header-container > .header .extension-icon-badge {
128128
width: 14px;
129129
height: 14px;
130130
line-height: 14px;
@@ -135,7 +135,7 @@
135135
justify-content: center;
136136
}
137137

138-
.extension-list-item > .details > .header-container > .header .extension-remote-badge > .codicon {
138+
.extension-list-item > .details > .header-container > .header .extension-icon-badge > .codicon {
139139
font-size: 12px;
140140
color: currentColor;
141141
}

src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
font-size: 128px !important;
4040
}
4141

42-
.extension-editor > .header > .icon-container .extension-remote-badge {
42+
.extension-editor > .header > .icon-container .extension-icon-badge {
4343
position: absolute;
4444
right: 0px;
4545
top: 88px;
@@ -53,7 +53,7 @@
5353
justify-content: center;
5454
}
5555

56-
.extension-editor > .header > .icon-container .extension-remote-badge .codicon {
56+
.extension-editor > .header > .icon-container .extension-icon-badge .codicon {
5757
color: currentColor;
5858
font-size: 28px;
5959
}

src/vs/workbench/contrib/extensions/browser/media/runtimeExtensionsEditor.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
padding: 10px 14px 10px 0;
5454
}
5555

56-
.runtime-extensions-editor .extension > .icon-container .extension-remote-badge .codicon {
56+
.runtime-extensions-editor .extension > .icon-container .extension-icon-badge .codicon {
5757
color: currentColor;
5858
}
5959

src/vs/workbench/contrib/mcp/browser/mcpServerEditor.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import { IEditorGroup } from '../../../services/editor/common/editorGroupsServic
3838
import { IExtensionService } from '../../../services/extensions/common/extensions.js';
3939
import { IHoverService } from '../../../../platform/hover/browser/hover.js';
4040
import { IMcpServerContainer, IMcpServerEditorOptions, IMcpWorkbenchService, IWorkbenchMcpServer, McpServerContainers, McpServerInstallState } from '../common/mcpTypes.js';
41-
import { InstallCountWidget, McpServerIconWidget, McpServerStatusWidget, McpServerWidget, onClick, PublisherWidget, RatingsWidget } from './mcpServerWidgets.js';
41+
import { InstallCountWidget, McpServerIconWidget, McpServerStatusWidget, McpServerWidget, onClick, PublisherWidget, RatingsWidget, McpServerScopeBadgeWidget } from './mcpServerWidgets.js';
4242
import { DropDownAction, InstallAction, InstallingLabelAction, ManageMcpServerAction, McpServerStatusAction, UninstallAction } from './mcpServerActions.js';
4343
import { McpServerEditorInput } from './mcpServerEditorInput.js';
4444
import { ILocalMcpServer, IMcpServerManifest, IMcpServerPackage, PackageType } from '../../../../platform/mcp/common/mcpManagement.js';
@@ -208,6 +208,7 @@ export class McpServerEditor extends EditorPane {
208208

209209
const iconContainer = append(header, $('.icon-container'));
210210
const iconWidget = this.instantiationService.createInstance(McpServerIconWidget, iconContainer);
211+
const scopeWidget = this.instantiationService.createInstance(McpServerScopeBadgeWidget, iconContainer);
211212

212213
const details = append(header, $('.details'));
213214
const title = append(details, $('.title'));
@@ -229,11 +230,13 @@ export class McpServerEditor extends EditorPane {
229230
subTitleEntryContainers.push(ratingsContainer);
230231
const ratingsWidget = this.instantiationService.createInstance(RatingsWidget, ratingsContainer, false);
231232

233+
232234
const widgets: McpServerWidget[] = [
233235
iconWidget,
234236
publisherWidget,
235237
installCountWidget,
236238
ratingsWidget,
239+
scopeWidget,
237240
];
238241

239242
const description = append(details, $('.description'));
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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 { Codicon } from '../../../../base/common/codicons.js';
7+
import { localize } from '../../../../nls.js';
8+
import { registerIcon } from '../../../../platform/theme/common/iconRegistry.js';
9+
10+
export const mcpServerIcon = registerIcon('mcp-server', Codicon.mcp, localize('mcpServer', 'Icon used for the MCP server.'));
11+
export const mcpServerRemoteIcon = registerIcon('mcp-server-remote', Codicon.remote, localize('mcpServerRemoteIcon', 'Icon to indicate that an MCP server is for the remote user scope.'));
12+
export const mcpServerWorkspaceIcon = registerIcon('mcp-server-workspace', Codicon.rootFolder, localize('mcpServerWorkspaceIcon', 'Icon to indicate that an MCP server is for the workspace scope.'));

src/vs/workbench/contrib/mcp/browser/mcpServerWidgets.ts

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,20 @@ import { IHoverService } from '../../../../platform/hover/browser/hover.js';
1818
import { IOpenerService } from '../../../../platform/opener/common/opener.js';
1919
import { verifiedPublisherIcon } from '../../../services/extensionManagement/common/extensionsIcons.js';
2020
import { installCountIcon, starEmptyIcon, starFullIcon, starHalfIcon } from '../../extensions/browser/extensionsIcons.js';
21-
import { IMcpServerContainer, IWorkbenchMcpServer, mcpServerIcon } from '../common/mcpTypes.js';
21+
import { IMcpServerContainer, IWorkbenchMcpServer } from '../common/mcpTypes.js';
2222
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
2323
import { ColorScheme } from '../../../../platform/theme/common/theme.js';
2424
import { Emitter, Event } from '../../../../base/common/event.js';
2525
import { McpServerStatusAction } from './mcpServerActions.js';
2626
import { reset } from '../../../../base/browser/dom.js';
27+
import { mcpServerIcon, mcpServerRemoteIcon, mcpServerWorkspaceIcon } from './mcpServerIcons.js';
2728
import { MarkdownString } from '../../../../base/common/htmlContent.js';
2829
import { renderMarkdown } from '../../../../base/browser/markdownRenderer.js';
2930
import { onUnexpectedError } from '../../../../base/common/errors.js';
30-
import { ExtensionHoverOptions } from '../../extensions/browser/extensionsWidgets.js';
31+
import { ExtensionHoverOptions, ExtensionIconBadge } from '../../extensions/browser/extensionsWidgets.js';
3132
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
3233
import { LocalMcpServerScope } from '../../../services/mcp/common/mcpWorkbenchManagementService.js';
34+
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
3335

3436
export abstract class McpServerWidget extends Disposable implements IMcpServerContainer {
3537
private _mcpServer: IWorkbenchMcpServer | null = null;
@@ -390,10 +392,17 @@ export class McpServerHoverWidget extends McpServerWidget {
390392
markdown.appendText(`\n`);
391393

392394
if (this.mcpServer.local?.scope === LocalMcpServerScope.Workspace) {
395+
markdown.appendMarkdown(`$(${mcpServerWorkspaceIcon.id})&nbsp;`);
393396
markdown.appendMarkdown(localize('workspace extension', "Workspace MCP Server"));
394397
markdown.appendText(`\n`);
395398
}
396399

400+
if (this.mcpServer.local?.scope === LocalMcpServerScope.RemoteUser) {
401+
markdown.appendMarkdown(`$(${mcpServerRemoteIcon.id})&nbsp;`);
402+
markdown.appendMarkdown(localize('remote user extension', "Remote MCP Server"));
403+
markdown.appendText(`\n`);
404+
}
405+
397406
if (this.mcpServer.description) {
398407
markdown.appendMarkdown(`${this.mcpServer.description}`);
399408
markdown.appendText(`\n`);
@@ -421,6 +430,52 @@ export class McpServerHoverWidget extends McpServerWidget {
421430

422431
}
423432

433+
export class McpServerScopeBadgeWidget extends McpServerWidget {
434+
435+
private readonly badge = this._register(new MutableDisposable<ExtensionIconBadge>());
436+
private element: HTMLElement;
437+
438+
constructor(
439+
readonly container: HTMLElement,
440+
@IInstantiationService private readonly instantiationService: IInstantiationService
441+
) {
442+
super();
443+
this.element = dom.append(this.container, dom.$(''));
444+
this.render();
445+
this._register(toDisposable(() => this.clear()));
446+
}
447+
448+
private clear(): void {
449+
this.badge.value?.element.remove();
450+
this.badge.clear();
451+
}
452+
453+
render(): void {
454+
this.clear();
455+
456+
const scope = this.mcpServer?.local?.scope;
457+
458+
if (!scope || scope === LocalMcpServerScope.User) {
459+
return;
460+
}
461+
462+
let icon: ThemeIcon;
463+
switch (scope) {
464+
case LocalMcpServerScope.Workspace: {
465+
icon = mcpServerWorkspaceIcon;
466+
break;
467+
}
468+
case LocalMcpServerScope.RemoteUser: {
469+
icon = mcpServerRemoteIcon;
470+
break;
471+
}
472+
}
473+
474+
this.badge.value = this.instantiationService.createInstance(ExtensionIconBadge, icon, undefined);
475+
dom.append(this.element, this.badge.value.element);
476+
}
477+
}
478+
424479
export class McpServerStatusWidget extends McpServerWidget {
425480

426481
private readonly renderDisposables = this._register(new MutableDisposable());

src/vs/workbench/contrib/mcp/browser/mcpServersView.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ import { IThemeService } from '../../../../platform/theme/common/themeService.js
2424
import { getLocationBasedViewColors } from '../../../browser/parts/views/viewPane.js';
2525
import { IViewletViewOptions } from '../../../browser/parts/views/viewsViewlet.js';
2626
import { IViewDescriptorService, IViewsRegistry, ViewContainerLocation, Extensions as ViewExtensions } from '../../../common/views.js';
27-
import { HasInstalledMcpServersContext, IMcpWorkbenchService, InstalledMcpServersViewId, IWorkbenchMcpServer, McpServerContainers, mcpServerIcon, McpServerInstallState } from '../common/mcpTypes.js';
27+
import { HasInstalledMcpServersContext, IMcpWorkbenchService, InstalledMcpServersViewId, IWorkbenchMcpServer, McpServerContainers, McpServerInstallState } from '../common/mcpTypes.js';
2828
import { DropDownAction, InstallAction, InstallingLabelAction, ManageMcpServerAction, McpServerStatusAction } from './mcpServerActions.js';
29-
import { PublisherWidget, InstallCountWidget, RatingsWidget, McpServerIconWidget, McpServerHoverWidget } from './mcpServerWidgets.js';
29+
import { PublisherWidget, InstallCountWidget, RatingsWidget, McpServerIconWidget, McpServerHoverWidget, McpServerScopeBadgeWidget } from './mcpServerWidgets.js';
3030
import { ActionRunner, IAction, Separator } from '../../../../base/common/actions.js';
3131
import { IActionViewItemOptions } from '../../../../base/browser/ui/actionbar/actionViewItems.js';
3232
import { IAllowedMcpServersService, IMcpGalleryService } from '../../../../platform/mcp/common/mcpManagement.js';
@@ -47,6 +47,7 @@ import { AbstractExtensionsListView } from '../../extensions/browser/extensionsV
4747
import { ExtensionListRendererOptions } from '../../extensions/browser/extensionsList.js';
4848
import { HoverPosition } from '../../../../base/browser/ui/hover/hoverWidget.js';
4949
import { IWorkbenchLayoutService, Position } from '../../../services/layout/browser/layoutService.js';
50+
import { mcpServerIcon } from './mcpServerIcons.js';
5051

5152
export interface McpServerListViewOptions {
5253
showWelcomeOnEmpty?: boolean;
@@ -363,6 +364,7 @@ class McpServerRenderer implements IListRenderer<IWorkbenchMcpServer, IMcpServer
363364
publisherWidget,
364365
this.instantiationService.createInstance(InstallCountWidget, installCount, true),
365366
this.instantiationService.createInstance(RatingsWidget, ratings, true),
367+
this.instantiationService.createInstance(McpServerScopeBadgeWidget, iconContainer),
366368
this.instantiationService.createInstance(McpServerHoverWidget, { target: root, position: this.options.hoverOptions.position }, mcpServerStatusAction)
367369
];
368370
const extensionContainers: McpServerContainers = this.instantiationService.createInstance(McpServerContainers, [...actions, ...widgets]);

src/vs/workbench/contrib/mcp/common/mcpTypes.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { equals as arraysEqual } from '../../../../base/common/arrays.js';
77
import { assertNever } from '../../../../base/common/assert.js';
88
import { decodeHex, encodeHex, VSBuffer } from '../../../../base/common/buffer.js';
99
import { CancellationToken } from '../../../../base/common/cancellation.js';
10-
import { Codicon } from '../../../../base/common/codicons.js';
1110
import { Event } from '../../../../base/common/event.js';
1211
import { IMarkdownString } from '../../../../base/common/htmlContent.js';
1312
import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js';
@@ -24,7 +23,6 @@ import { createDecorator } from '../../../../platform/instantiation/common/insta
2423
import { IInstallableMcpServer as IInstallableMcpServer, IGalleryMcpServer, IQueryOptions, IMcpServerManifest } from '../../../../platform/mcp/common/mcpManagement.js';
2524
import { IMcpDevModeConfig, IMcpServerConfiguration } from '../../../../platform/mcp/common/mcpPlatformTypes.js';
2625
import { StorageScope } from '../../../../platform/storage/common/storage.js';
27-
import { registerIcon } from '../../../../platform/theme/common/iconRegistry.js';
2826
import { IWorkspaceFolder, IWorkspaceFolderData } from '../../../../platform/workspace/common/workspace.js';
2927
import { IWorkbenchLocalMcpServer, IWorkbencMcpServerInstallOptions } from '../../../services/mcp/common/mcpWorkbenchManagementService.js';
3028
import { ToolProgress } from '../../chat/common/languageModelToolsService.js';
@@ -662,7 +660,6 @@ export class McpServerContainers extends Disposable {
662660
export const McpServersGalleryEnabledContext = new RawContextKey<boolean>('mcpServersGalleryEnabled', false);
663661
export const HasInstalledMcpServersContext = new RawContextKey<boolean>('hasInstalledMcpServers', true);
664662
export const InstalledMcpServersViewId = 'workbench.views.mcp.installed';
665-
export const mcpServerIcon = registerIcon('mcp-server', Codicon.mcp, localize('mcpServer', 'Icon used for the MCP server.'));
666663

667664
export namespace McpResourceURI {
668665
export const scheme = 'mcp-resource';

0 commit comments

Comments
 (0)