Skip to content

Prototype redesign of customizations plugin page#322043

Draft
hawkticehurst wants to merge 3 commits into
mainfrom
agents/can-you-kick-off-a-pi-coding-agent-3d251f1f
Draft

Prototype redesign of customizations plugin page#322043
hawkticehurst wants to merge 3 commits into
mainfrom
agents/can-you-kick-off-a-pi-coding-agent-3d251f1f

Conversation

@hawkticehurst

Copy link
Copy Markdown
Member

WIP

@hawkticehurst hawkticehurst self-assigned this Jun 19, 2026
Copilot AI review requested due to automatic review settings June 19, 2026 05:29
@hawkticehurst hawkticehurst changed the title Prototype design for plugin page in customizations modal Prototype redesign of customizations plugin page Jun 19, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prototypes a redesigned Plugins experience in the AI Customizations management editor, shifting the default surface toward a card-based “home” while retaining WorkbenchList for search and list-based interactions.

Changes:

  • Introduces a card-based plugins home surface, plus a browse/search experience that mixes installed/remote/marketplace results.
  • Enhances plugin detail rendering to include provenance/facts, contribution inventory, and inline management actions.
  • Updates styling and component fixtures to support the redesigned layouts and new marketplace recommendation signal (recommendedPlugins).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts Updates fixture mocks (adds recommendedPlugins) and switches browse-mode activation to the widget API.
src/vs/workbench/contrib/chat/browser/aiCustomization/pluginListWidget.ts Reworks plugin list UI: card home surface, search headers, recommended badges, and marketplace/installed search blending.
src/vs/workbench/contrib/chat/browser/aiCustomization/media/aiCustomizationManagement.css Adds/adjusts CSS for the new plugin list rows, card surfaces, and richer embedded detail layout.
src/vs/workbench/contrib/chat/browser/aiCustomization/embeddedAgentPluginDetail.ts Expands embedded plugin detail with install/enable/disable/uninstall actions, facts, copy path, and grouped contributions.
src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationManagementEditor.ts Wires new embedded-detail events to open contributed artifacts/sections and handle uninstall navigation.
src/vs/sessions/AI_CUSTOMIZATIONS.md Documents the new Plugins section UX and behaviors.

Comment on lines +407 to +420
function formatSourceKind(sourceKind: PluginSourceKind): string {
switch (sourceKind) {
case PluginSourceKind.GitHub:
return localize('pluginDetailSourceGitHub', "GitHub");
case PluginSourceKind.GitUrl:
return localize('pluginDetailSourceGitUrl', "Git URL");
case PluginSourceKind.Npm:
return localize('pluginDetailSourceNpm', "npm");
case PluginSourceKind.Pip:
return localize('pluginDetailSourcePip', "pip");
case PluginSourceKind.RelativePath:
return localize('pluginDetailSourceRelativePath', "Marketplace repository");
}
}
Comment on lines +817 to +818
margin-inline-start: -15px;
margin-inline-end: 20px;
Comment on lines +230 to +234
Installed plugin cards show:
- plugin identity, source/provenance, enabled/disabled state, and description
- contribution preview chips derived from real installed plugin data (`agents`, `skills`, `commands`, `instructions`, `mcpServerDefinitions`, `hooks`)
- explicit action buttons (`View`, `More Actions`) rather than making the card itself clickable

Comment on lines +1083 to +1103
private addCardActivation(card: HTMLElement, label: string, callback: () => void): void {
card.tabIndex = 0;
card.setAttribute('role', 'button');
card.setAttribute('aria-label', label);
this.rememberCardFocusElement(card);
this.cardDisposables.add(DOM.addDisposableListener(card, 'click', e => {
if (e.defaultPrevented) {
return;
}
callback();
}));
this.cardDisposables.add(DOM.addDisposableListener(card, 'keydown', e => {
if (e.target !== card) {
return;
}
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
callback();
}
}));
}
Comment on lines +1512 to +1535
private async queryPluginSearch(): Promise<void> {
this.marketplaceCts?.dispose(true);
const cts = this.marketplaceCts = new CancellationTokenSource();
try {
const plugins = await this.pluginMarketplaceService.fetchMarketplacePlugins(cts.token);
if (cts.token.isCancellationRequested || this.browseMode) {
return;
}
const query = this.searchQuery.toLowerCase().trim();
const filtered = query
? plugins.filter(p => p.name.toLowerCase().includes(query) || p.description.toLowerCase().includes(query) || p.marketplace.toLowerCase().includes(query))
: plugins;
const installedUris = new Set(this.agentPluginService.plugins.get().map(p => p.uri.toString()));
this.marketplaceItems = filtered
.filter(p => {
const expectedUri = this.pluginInstallService.getPluginInstallUri(p);
return !installedUris.has(expectedUri.toString());
})
.map(marketplacePluginToItem);
} catch {
this.marketplaceItems = [];
}
await this.filterPlugins();
}
@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Screenshot Changes

Base: 8c08e04f Current: 9381b8cf

Changed (54)

chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpBrowseMode/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpBrowseMode/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginBrowseMode/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginBrowseMode/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTabScrolled/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTabScrolled/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginsTabScrolled/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginsTabScrolled/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTabNarrow/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTabNarrow/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServerDetail/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServerDetail/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServerDetailNarrow/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServerDetailNarrow/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginDetail/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginDetail/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginDetailNarrow/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginDetailNarrow/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/EmbeddedMcpDetailWorkspace/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/EmbeddedMcpDetailWorkspace/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/EmbeddedMcpDetailUser/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/EmbeddedMcpDetailUser/Light
Before After
before after
editor/inlineChatAffordance/InlineChatAffordance/Dark
Before After
before after
editor/inlineChatAffordance/InlineChatAffordance/Light
Before After
before after
editor/inlineCompletions/other/HintsToolbar/Dark
Before After
before after
editor/inlineCompletions/other/HintsToolbar/Light
Before After
before after
editor/inlineCompletions/other/HintsToolbarHovered/Dark
Before After
before after
editor/inlineCompletions/other/HintsToolbarHovered/Light
Before After
before after
editor/inlineCompletions/views/SideBySideViewSmall/Dark
Before After
before after
editor/inlineCompletions/views/SideBySideViewSmall/Light
Before After
before after
editor/inlineCompletions/views/SideBySideViewWide/Dark
Before After
before after
editor/inlineCompletions/views/SideBySideViewWide/Light
Before After
before after
editor/inlineCompletions/views/WordReplacementView/Dark
Before After
before after
editor/inlineCompletions/views/WordReplacementView/Light
Before After
before after
editor/inlineCompletions/views/DeletionView/Dark
Before After
before after
editor/inlineCompletions/views/DeletionView/Light
Before After
before after
editor/inlineCompletions/views/LineReplacementView/Dark
Before After
before after
editor/inlineCompletions/views/LineReplacementView/Light
Before After
before after
editor/multiDiffEditor/MultiDiffEditor/Dark
Before After
before after
editor/multiDiffEditor/MultiDiffEditor/Light
Before After
before after
editor/multiDiffEditor/MultiDiffEditorIncrementalPending/Dark
Before After
before after
editor/multiDiffEditor/MultiDiffEditorIncrementalPending/Light
Before After
before after
editor/multiDiffEditor/MultiDiffEditorIncrementalResolved/Dark
Before After
before after
editor/multiDiffEditor/MultiDiffEditorIncrementalResolved/Light
Before After
before after
editor/multiDiffEditor/MultiDiffEditorDocumentSwapAfter/Dark
Before After
before after
editor/multiDiffEditor/MultiDiffEditorDocumentSwapAfter/Light
Before After
before after
editor/suggestWidget/MethodCompletions/Dark
Before After
before after
editor/suggestWidget/MethodCompletions/Light
Before After
before after
peekReference/PeekReferences/Dark
Before After
before after
peekReference/PeekReferences/Light
Before After
before after

Errored (6)

Fixtures that failed to render — no screenshot was produced.

chat/aiCustomizations/aiCustomizationManagementEditor/EmbeddedPluginDetailInstalled/Dark — [createInstance] EmbeddedAgentPluginDetail depends on UNKNOWN service agentPluginService.
Error: [createInstance] EmbeddedAgentPluginDetail depends on UNKNOWN service agentPluginService.
    at TestInstantiationService._throwIfStrict (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:392:10)
    at TestInstantiationService._createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:142:10)
    at TestInstantiationService.createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:128:18)
    at TestInstantiationService.createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts:62:16)
    at renderEmbeddedPluginDetail (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts:1191:62)
    at Object.render (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts:1569:18)
    at actualRender (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:982:29)
    at Object.render (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:1017:4)
    at Le.waitForRendering (file:///home/runner/work/vscode/vscode/build/rspack/node_modules/@vscode/component-explorer/src/core/ComponentRenderer.ts:203:19)
    at Mt.renderFixture (file:///home/runner/work/vscode/vscode/build/rspack/node_modules/@vscode/component-explorer/src/modes/HeadlessMode.ts:158:19)
    at async <anonymous>:316:30
chat/aiCustomizations/aiCustomizationManagementEditor/EmbeddedPluginDetailInstalled/Light — [createInstance] EmbeddedAgentPluginDetail depends on UNKNOWN service agentPluginService.
Error: [createInstance] EmbeddedAgentPluginDetail depends on UNKNOWN service agentPluginService.
    at TestInstantiationService._throwIfStrict (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:392:10)
    at TestInstantiationService._createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:142:10)
    at TestInstantiationService.createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:128:18)
    at TestInstantiationService.createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts:62:16)
    at renderEmbeddedPluginDetail (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts:1191:62)
    at Object.render (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts:1569:18)
    at actualRender (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:982:29)
    at Object.render (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:1017:4)
    at Le.waitForRendering (file:///home/runner/work/vscode/vscode/build/rspack/node_modules/@vscode/component-explorer/src/core/ComponentRenderer.ts:203:19)
    at Mt.renderFixture (file:///home/runner/work/vscode/vscode/build/rspack/node_modules/@vscode/component-explorer/src/modes/HeadlessMode.ts:158:19)
    at async <anonymous>:316:30
chat/aiCustomizations/aiCustomizationManagementEditor/EmbeddedPluginDetailMarketplace/Dark — [createInstance] EmbeddedAgentPluginDetail depends on UNKNOWN service agentPluginService.
Error: [createInstance] EmbeddedAgentPluginDetail depends on UNKNOWN service agentPluginService.
    at TestInstantiationService._throwIfStrict (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:392:10)
    at TestInstantiationService._createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:142:10)
    at TestInstantiationService.createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:128:18)
    at TestInstantiationService.createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts:62:16)
    at renderEmbeddedPluginDetail (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts:1191:62)
    at Object.render (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts:1575:18)
    at actualRender (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:982:29)
    at Object.render (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:1017:4)
    at Le.waitForRendering (file:///home/runner/work/vscode/vscode/build/rspack/node_modules/@vscode/component-explorer/src/core/ComponentRenderer.ts:203:19)
    at Mt.renderFixture (file:///home/runner/work/vscode/vscode/build/rspack/node_modules/@vscode/component-explorer/src/modes/HeadlessMode.ts:158:19)
    at async <anonymous>:316:30
chat/aiCustomizations/aiCustomizationManagementEditor/EmbeddedPluginDetailMarketplace/Light — [createInstance] EmbeddedAgentPluginDetail depends on UNKNOWN service agentPluginService.
Error: [createInstance] EmbeddedAgentPluginDetail depends on UNKNOWN service agentPluginService.
    at TestInstantiationService._throwIfStrict (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:392:10)
    at TestInstantiationService._createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:142:10)
    at TestInstantiationService.createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:128:18)
    at TestInstantiationService.createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts:62:16)
    at renderEmbeddedPluginDetail (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts:1191:62)
    at Object.render (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts:1575:18)
    at actualRender (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:982:29)
    at Object.render (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:1017:4)
    at Le.waitForRendering (file:///home/runner/work/vscode/vscode/build/rspack/node_modules/@vscode/component-explorer/src/core/ComponentRenderer.ts:203:19)
    at Mt.renderFixture (file:///home/runner/work/vscode/vscode/build/rspack/node_modules/@vscode/component-explorer/src/modes/HeadlessMode.ts:158:19)
    at async <anonymous>:316:30
chat/aiCustomizations/aiCustomizationManagementEditor/EmbeddedPluginDetailEmpty/Dark — [createInstance] EmbeddedAgentPluginDetail depends on UNKNOWN service agentPluginService.
Error: [createInstance] EmbeddedAgentPluginDetail depends on UNKNOWN service agentPluginService.
    at TestInstantiationService._throwIfStrict (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:392:10)
    at TestInstantiationService._createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:142:10)
    at TestInstantiationService.createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:128:18)
    at TestInstantiationService.createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts:62:16)
    at renderEmbeddedPluginDetail (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts:1191:62)
    at Object.render (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts:1581:18)
    at actualRender (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:982:29)
    at Object.render (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:1017:4)
    at Le.waitForRendering (file:///home/runner/work/vscode/vscode/build/rspack/node_modules/@vscode/component-explorer/src/core/ComponentRenderer.ts:203:19)
    at Mt.renderFixture (file:///home/runner/work/vscode/vscode/build/rspack/node_modules/@vscode/component-explorer/src/modes/HeadlessMode.ts:158:19)
    at async <anonymous>:316:30
chat/aiCustomizations/aiCustomizationManagementEditor/EmbeddedPluginDetailEmpty/Light — [createInstance] EmbeddedAgentPluginDetail depends on UNKNOWN service agentPluginService.
Error: [createInstance] EmbeddedAgentPluginDetail depends on UNKNOWN service agentPluginService.
    at TestInstantiationService._throwIfStrict (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:392:10)
    at TestInstantiationService._createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:142:10)
    at TestInstantiationService.createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/common/instantiationService.ts:128:18)
    at TestInstantiationService.createInstance (file:///home/runner/work/vscode/vscode/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts:62:16)
    at renderEmbeddedPluginDetail (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts:1191:62)
    at Object.render (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/sessions/aiCustomizationManagementEditor.fixture.ts:1581:18)
    at actualRender (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:982:29)
    at Object.render (file:///home/runner/work/vscode/vscode/src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:1017:4)
    at Le.waitForRendering (file:///home/runner/work/vscode/vscode/build/rspack/node_modules/@vscode/component-explorer/src/core/ComponentRenderer.ts:203:19)
    at Mt.renderFixture (file:///home/runner/work/vscode/vscode/build/rspack/node_modules/@vscode/component-explorer/src/modes/HeadlessMode.ts:158:19)
    at async <anonymous>:316:30

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants