Skip to content

Commit a9b9a05

Browse files
pfaffedevtools-frontend-scoped@luci-project-accounts.iam.gserviceaccount.com
authored andcommitted
[webmcp] Copyable names and descriptions in the tool list
Bug: 494516094 Change-Id: I68caea5f95784af03bb4b1df9c6d6ac019e2e1bf Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/7766596 Reviewed-by: Eric Leese <leese@chromium.org> Commit-Queue: Eric Leese <leese@chromium.org> Auto-Submit: Philip Pfaffe <pfaffe@chromium.org>
1 parent dfec07e commit a9b9a05

File tree

4 files changed

+67
-3
lines changed

4 files changed

+67
-3
lines changed

front_end/panels/application/WebMCPView.test.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@
44

55
import type {JSONSchema7} from 'json-schema';
66

7+
import * as Host from '../../core/host/host.js';
78
import * as Platform from '../../core/platform/platform.js';
89
import * as SDK from '../../core/sdk/sdk.js';
910
import * as Protocol from '../../generated/protocol.js';
1011
import * as Bindings from '../../models/bindings/bindings.js';
1112
import * as WebMCP from '../../models/web_mcp/web_mcp.js';
1213
import * as Workspace from '../../models/workspace/workspace.js';
13-
import {findMenuItemWithLabel, getMenuForToolbarButton} from '../../testing/ContextMenuHelpers.js';
14+
import {
15+
findMenuItemWithLabel,
16+
getContextMenuForElement,
17+
getMenuForToolbarButton
18+
} from '../../testing/ContextMenuHelpers.js';
1419
import {assertScreenshot, renderElementIntoDOM} from '../../testing/DOMHelpers.js';
1520
import {createTarget, describeWithEnvironment, updateHostConfig} from '../../testing/EnvironmentHelpers.js';
1621
import {StubStackTrace} from '../../testing/StackTraceHelpers.js';
@@ -148,6 +153,40 @@ describeWithEnvironment('WebMCPView (View)', () => {
148153
await assertScreenshot('application/webmcp_view.png');
149154
});
150155

156+
it('shows a context menu when right-clicking a tool', async () => {
157+
const copyTextStub = sinon.stub(Host.InspectorFrontendHost.InspectorFrontendHostInstance, 'copyText');
158+
const sdkTarget = createTarget();
159+
const container = document.createElement('div');
160+
renderElementIntoDOM(container);
161+
162+
const tools = [
163+
createTool('test_tool', 'A test tool description', 'frame1' as Protocol.Page.FrameId, sdkTarget),
164+
];
165+
166+
DEFAULT_VIEW(
167+
{
168+
...createDefaultViewInput(),
169+
tools,
170+
},
171+
{}, container);
172+
173+
const toolItem = container.querySelector('.tool-item');
174+
assert.isNotNull(toolItem);
175+
176+
const contextMenu = getContextMenuForElement(toolItem);
177+
const copyNameItem = findMenuItemWithLabel(contextMenu.defaultSection(), 'Copy name');
178+
const copyDescItem = findMenuItemWithLabel(contextMenu.defaultSection(), 'Copy description');
179+
180+
assert.isDefined(copyNameItem);
181+
assert.isDefined(copyDescItem);
182+
183+
contextMenu.invokeHandler(copyNameItem.id());
184+
sinon.assert.calledWith(copyTextStub, 'test_tool');
185+
186+
contextMenu.invokeHandler(copyDescItem.id());
187+
sinon.assert.calledWith(copyTextStub, 'A test tool description');
188+
});
189+
151190
it('renders a list of tools', async () => {
152191
updateHostConfig({devToolsWebMCPSupport: {enabled: true}});
153192
const sdkTarget = createTarget();

front_end/panels/application/WebMCPView.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import '../../ui/legacy/legacy.js';
1111
import type {JSONSchema7, JSONSchema7Definition} from 'json-schema';
1212

1313
import * as Common from '../../core/common/common.js';
14+
import * as Host from '../../core/host/host.js';
1415
import * as i18n from '../../core/i18n/i18n.js';
1516
import * as Platform from '../../core/platform/platform.js';
1617
import * as SDK from '../../core/sdk/sdk.js';
@@ -158,6 +159,14 @@ const UIStrings = {
158159
* @example {1} PH1
159160
*/
160161
inProgressCount: '{PH1} In Progress',
162+
/**
163+
* @description Context menu action to copy the name of a tool
164+
*/
165+
copyName: 'Copy name',
166+
/**
167+
* @description Context menu action to copy the description of a tool
168+
*/
169+
copyDescription: 'Copy description',
161170
} as const;
162171
const str_ = i18n.i18n.registerUIStrings('panels/application/WebMCPView.ts', UIStrings);
163172
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -350,6 +359,16 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
350359
return i18nString(UIStrings.inProgress);
351360
}
352361
};
362+
const onToolContextMenu = (event: Event, tool: WebMCP.WebMCPModel.Tool): void => {
363+
const contextMenu = new UI.ContextMenu.ContextMenu(event);
364+
contextMenu.defaultSection().appendItem(i18nString(UIStrings.copyName), () => {
365+
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(tool.name);
366+
}, {jslogContext: 'webmcp.copy-tool-name'});
367+
contextMenu.defaultSection().appendItem(i18nString(UIStrings.copyDescription), () => {
368+
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(tool.description);
369+
}, {jslogContext: 'webmcp.copy-tool-description'});
370+
void contextMenu.show();
371+
};
353372
// clang-format off
354373
render(html`
355374
<style>${webMCPViewStyles}</style>
@@ -491,7 +510,8 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
491510
const groups = getIconGroupsFromStats(toolStats);
492511
return html`
493512
<div class=${Directives.classMap({'tool-item': true, selected: tool === input.selectedTool})}
494-
@click=${() => input.onToolSelect(tool)}>
513+
@click=${() => input.onToolSelect(tool)}
514+
@contextmenu=${(e: Event) => onToolContextMenu(e, tool)}>
495515
<div class="tool-name-container">
496516
<div class="tool-name source-code">${tool.name}</div>
497517
${groups.length > 0 ? html`<icon-button .data=${

front_end/panels/application/webMCPView.css

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
height: 100%;
7878
display: flex;
7979
flex-direction: column;
80-
overflow: auto;
80+
overflow: hidden;
8181
}
8282

8383
.tool-details-grid {
@@ -86,6 +86,7 @@
8686
gap: 0 var(--sys-size-16);
8787
padding: calc(0.5*var(--sys-size-6)) var(--sys-size-8);
8888
align-items: flex-start;
89+
overflow-y: auto;
8990

9091
.label {
9192
color: var(--sys-color-on-surface-subtle);
@@ -94,6 +95,8 @@
9495
}
9596

9697
.value {
98+
user-select: text;
99+
97100
&.source-code {
98101
color: var(--sys-color-token-attribute);
99102
}

front_end/ui/visual_logging/KnownContextValues.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4350,6 +4350,8 @@ export const knownContextValues = new Set([
43504350
'webmcp.call-inputs',
43514351
'webmcp.call-outputs',
43524352
'webmcp.completed',
4353+
'webmcp.copy-tool-description',
4354+
'webmcp.copy-tool-name',
43534355
'webmcp.declarative',
43544356
'webmcp.error',
43554357
'webmcp.imperative',

0 commit comments

Comments
 (0)