diff --git a/src/vs/workbench/contrib/chat/browser/aiCustomization/mcpListWidget.ts b/src/vs/workbench/contrib/chat/browser/aiCustomization/mcpListWidget.ts index bf4506fc8b2fc..fdca7555780c5 100644 --- a/src/vs/workbench/contrib/chat/browser/aiCustomization/mcpListWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/aiCustomization/mcpListWidget.ts @@ -601,13 +601,6 @@ export class McpServerItemRenderer extends Disposable implements IListRenderer this.updateActionsTabbability(templateData)); this.updateActionsTabbability(templateData); return; @@ -935,6 +928,11 @@ export function updateMcpCompatibilityMessage(message: HTMLElement, kind: Custom }, }, message); const migrationLink = message.firstElementChild as HTMLAnchorElement | null; + const iconTheme = kind === 'unsupported' ? Codicon.error : Codicon.warning; + const icon = $('span.mcp-server-compatibility-icon'); + icon.classList.add(...ThemeIcon.asClassNameArray(iconTheme)); + icon.setAttribute('aria-hidden', 'true'); + message.insertBefore(icon, message.firstChild); if (migrationLink) { migrationLink.href = '#'; migrationLink.tabIndex = -1; @@ -944,17 +942,6 @@ export function updateMcpCompatibilityMessage(message: HTMLElement, kind: Custom return migrationLink ?? undefined; } -function updateMcpCompatibilityIcon(icon: HTMLElement, kind: CustomizationMcpServerCompatibilityKind | undefined, runtimeIcon: ThemeIcon | undefined): void { - const compatibility = getMcpCompatibilityPresentation(kind); - if (runtimeIcon || !compatibility) { - return; - } - const iconTheme = kind === 'unsupported' ? Codicon.error : Codicon.warning; - icon.className = `mcp-server-state-icon ${ThemeIcon.asClassNameArray(iconTheme).join(' ')} compatibility ${compatibility.className}`; - icon.style.display = ''; - icon.setAttribute('aria-label', compatibility.label); -} - export function getMcpStatusPresentation(state: McpStatusKind | undefined, disabledReason?: CustomizationDisabledReason): IMcpStatusPresentation | undefined { if (state === undefined) { return undefined; @@ -2775,7 +2762,6 @@ export class McpListWidget extends Disposable { getMcpEntryAriaLabel(entry, this.workspaceService.isSessionsWindow, compatibilityKind, this.labelService, this.agentPluginService, this.extensionsWorkbenchService), this.getInstalledEntryDescription(entry), ); - updateMcpCompatibilityIcon(statusIcon, compatibilityKind, getMcpStatusPresentation(getMcpStatusKind(entry, this.workspaceService.isSessionsWindow))?.icon); start.update(); showOutput.update(); })); @@ -2796,7 +2782,6 @@ export class McpListWidget extends Disposable { getMcpEntryAriaLabel(entry, this.workspaceService.isSessionsWindow, compatibilityKind, this.labelService, this.agentPluginService, this.extensionsWorkbenchService), this.getInstalledEntryDescription(entry), ); - updateMcpCompatibilityIcon(statusIcon, compatibilityKind, getMcpStatusPresentation(getMcpStatusKind(entry, this.workspaceService.isSessionsWindow))?.icon); signIn?.update(); start.update(); showOutput.update(); diff --git a/src/vs/workbench/contrib/chat/browser/aiCustomization/media/aiCustomizationManagement.css b/src/vs/workbench/contrib/chat/browser/aiCustomization/media/aiCustomizationManagement.css index 2de249eca1757..029d7658b2bbd 100644 --- a/src/vs/workbench/contrib/chat/browser/aiCustomization/media/aiCustomizationManagement.css +++ b/src/vs/workbench/contrib/chat/browser/aiCustomization/media/aiCustomizationManagement.css @@ -2669,6 +2669,15 @@ per-word capitalization does not survive translation. */ color: var(--vscode-errorForeground); } +.ai-customization-management-editor .mcp-server-compatibility-message > .mcp-server-compatibility-icon.codicon { + margin-right: var(--vscode-spacing-size40); + font-size: var(--vscode-codiconFontSize-compact); + color: inherit; + position: relative; + top: -1px; + vertical-align: text-bottom; +} + .mcp-server-item .mcp-server-source-path.source-link + .mcp-server-compatibility-message::before { content: "ยท "; color: var(--vscode-descriptionForeground); @@ -2791,14 +2800,6 @@ per-word capitalization does not survive translation. */ color: var(--vscode-errorForeground); } -.plugin-list-widget .mcp-server-state-icon.compatibility { - color: var(--vscode-chat-mcpCompatibilityWarningForeground); -} - -.plugin-list-widget .mcp-server-state-icon.compatibility.unsupported { - color: var(--vscode-errorForeground); -} - .plugin-list-widget .mcp-server-state-icon.starting { color: var(--vscode-progressBar-background, var(--vscode-icon-foreground)); } diff --git a/src/vs/workbench/contrib/chat/test/browser/aiCustomization/mcpListWidget.test.ts b/src/vs/workbench/contrib/chat/test/browser/aiCustomization/mcpListWidget.test.ts index f73a34bb2b091..d905a39929820 100644 --- a/src/vs/workbench/contrib/chat/test/browser/aiCustomization/mcpListWidget.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/aiCustomization/mcpListWidget.test.ts @@ -778,6 +778,8 @@ suite('mcpListWidget', () => { ], messageClass: message.className, messageText: message.textContent, + messageIcon: message.querySelector('.mcp-server-compatibility-icon')?.className, + messageIconAriaHidden: message.querySelector('.mcp-server-compatibility-icon')?.getAttribute('aria-hidden'), messageDisplay: message.style.display, linkHref: message.querySelector('.mcp-server-compatibility-link')?.getAttribute('href'), migrationRequests, @@ -790,6 +792,8 @@ suite('mcpListWidget', () => { ], messageClass: 'mcp-server-compatibility-message partially-supported', messageText: 'Partially supported. See Migrations for details.', + messageIcon: 'mcp-server-compatibility-icon codicon codicon-warning', + messageIconAriaHidden: 'true', messageDisplay: '', linkHref: '#', migrationRequests: 1, @@ -2199,7 +2203,7 @@ suite('mcpListWidget', () => { assert.strictEqual(ctx.templateData.container.style.minHeight, '44px'); }); - test('compatibility issues use severity-specific icons without runtime status', () => { + test('compatibility issues use severity-specific icons at the beginning of their messages', () => { const render = (kind: 'unsupported' | 'partiallySupported') => { const ctx = createRenderer(createAgentHostServer(), true, false, undefined, kind); disposables.add(ctx.store); @@ -2210,7 +2214,8 @@ suite('mcpListWidget', () => { ctx.notifyUnchanged(); return { message: ctx.templateData.compatibilityMessage.textContent, - icon: ctx.templateData.actions.querySelector('.mcp-server-state-icon.compatibility')?.className, + messageIcon: ctx.templateData.compatibilityMessage.querySelector('.mcp-server-compatibility-icon')?.className, + actionIcon: ctx.templateData.actions.querySelector('.mcp-server-state-icon.compatibility')?.className, badges: ctx.templateData.container.querySelectorAll('.plugin-list-item-status').length, focusedLinkTabIndex, unfocusedLinkTabIndex: ctx.templateData.compatibilityLink?.tabIndex, @@ -2224,7 +2229,8 @@ suite('mcpListWidget', () => { }, { unsupported: { message: 'Unsupported. See Migrations for details.', - icon: 'mcp-server-state-icon codicon codicon-error compatibility unsupported', + messageIcon: 'mcp-server-compatibility-icon codicon codicon-error', + actionIcon: undefined, badges: 0, focusedLinkTabIndex: 0, unfocusedLinkTabIndex: -1, @@ -2232,7 +2238,8 @@ suite('mcpListWidget', () => { }, partiallySupported: { message: 'Partially supported. See Migrations for details.', - icon: 'mcp-server-state-icon codicon codicon-warning compatibility partially-supported', + messageIcon: 'mcp-server-compatibility-icon codicon codicon-warning', + actionIcon: undefined, badges: 0, focusedLinkTabIndex: 0, unfocusedLinkTabIndex: -1, diff --git a/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts b/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts index 5407c505cce7f..ddaa709804980 100644 --- a/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts +++ b/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts @@ -2931,13 +2931,13 @@ export default defineThemedFixtureGroup({ path: 'chat/aiCustomizations/' }, { McpServersTabCopilotCompatibility: defineComponentFixture({ labels: { kind: 'screenshot', blocksCi: false }, additionalThemes: ['light2026', 'lightHighContrast'], - expectedVisualDescriptions: ['With the Copilot harness selected, Unsupported uses a red error icon and red message while Partially supported uses a yellow warning icon and yellow message. Both messages include a Migrations link; configuration file paths and compatibility badges do not appear.'], + expectedVisualDescriptions: ['With the Copilot harness selected, Unsupported begins its red message with a compact red error icon while Partially supported begins its yellow message with a compact yellow warning icon. Both messages include a Migrations link; compatibility icons do not appear beside the row actions, and configuration file paths and compatibility badges do not appear.'], render: ctx => renderEditor(ctx, { sessionResource: agentHostCopilotSessionResource, selectedSection: AICustomizationManagementSection.McpServers, mcpServerCompatibility: [ { id: 'component-explorer', kind: 'partiallySupported' }, - { id: 'mcp-postgres', kind: 'unsupported' }, + { id: 'mcp-github', kind: 'unsupported' }, ], }), }), @@ -2945,7 +2945,7 @@ export default defineThemedFixtureGroup({ path: 'chat/aiCustomizations/' }, { McpServersAllStates: defineComponentFixture({ labels: { kind: 'screenshot', blocksCi: false }, additionalThemes: ['light2026', 'darkHighContrast', 'lightHighContrast'], - expectedVisualDescriptions: ['Every installed MCP row has the same height as the default running row. The tree presents all states without configuration file paths: running has no indicator, starting has a spinner, authentication shows Sign In without an auth icon, error retains the ordinary description and shows a red error icon plus Show Output before the switch, stopped shows a Start button styled like Sign In, disabled rows are dimmed with switches off and labels for Globally, Workspace, and Session scopes, Unsupported uses a red error treatment, and Partially supported uses a yellow warning treatment. Compatibility messages include a Migrations link; no state badges or inline error snippets appear.'], + expectedVisualDescriptions: ['Every installed MCP row has the same height as the default running row. The tree presents all states without configuration file paths: running has no indicator, starting has a spinner, authentication shows Sign In without an auth icon, error retains the ordinary description and shows a red error icon plus Show Output before the switch, stopped shows a Start button styled like Sign In, disabled rows are dimmed with switches off and labels for Globally, Workspace, and Session scopes, Unsupported begins its red message with a compact error icon, and Partially supported begins its yellow message with a compact warning icon. Compatibility messages include a Migrations link; compatibility icons do not appear beside row actions, and no state badges or inline error snippets appear.'], render: async ctx => { await renderEditor(ctx, { sessionResource: agentHostCopilotSessionResource,