Skip to content

Commit

Permalink
Add context menu to copy Network request payload
Browse files Browse the repository at this point in the history
Fixed: 40206460
Change-Id: I6abce1ebeeeff6f7d5116ad2da3fcf33f836f57c
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6169136
Commit-Queue: Yang Guo <[email protected]>
Reviewed-by: Danil Somsikov <[email protected]>
  • Loading branch information
hashseed authored and Devtools-frontend LUCI CQ committed Jan 14, 2025
1 parent 8b387fb commit ba3c245
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 9 deletions.
22 changes: 14 additions & 8 deletions front_end/panels/network/RequestPayloadView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,13 @@ import requestPayloadTreeStyles from './requestPayloadTree.css.js';
import requestPayloadViewStyles from './requestPayloadView.css.js';
const UIStrings = {
/**
*@description A context menu item in the Watch Expressions Sidebar Pane of the Sources panel and Network pane request.
*@description A context menu item Payload View of the Network panel to copy a parsed value.
*/
copyValue: 'Copy value',
/**
*@description A context menu item Payload View of the Network panel to copy the payload.
*/
copyPayload: 'Copy',
/**
* @description Text in Request Payload View of the Network panel. This is a noun-phrase meaning the
* payload of a network request.
Expand Down Expand Up @@ -160,17 +164,16 @@ export class RequestPayloadView extends UI.Widget.VBox {
this.request.removeEventListener(SDK.NetworkRequest.Events.REQUEST_HEADERS_CHANGED, this.refreshFormData, this);
}

private addEntryContextMenuHandler(treeElement: UI.TreeOutline.TreeElement, value: string): void {
private addEntryContextMenuHandler(
treeElement: UI.TreeOutline.TreeElement, menuItem: string, jslogContext: string, getValue: () => string): void {
treeElement.listItemElement.addEventListener('contextmenu', event => {
event.consume(true);
const contextMenu = new UI.ContextMenu.ContextMenu(event);
const decodedValue = decodeURIComponent(value);
const copyDecodedValueHandler = (): void => {
const copyValueHandler = (): void => {
Host.userMetrics.actionTaken(Host.UserMetrics.Action.NetworkPanelCopyValue);
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(decodedValue);
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(getValue());
};
contextMenu.clipboardSection().appendItem(
i18nString(UIStrings.copyValue), copyDecodedValueHandler, {jslogContext: 'copy-value'});
contextMenu.clipboardSection().appendItem(menuItem, copyValueHandler, {jslogContext});
void contextMenu.show();
});
}
Expand Down Expand Up @@ -249,8 +252,10 @@ export class RequestPayloadView extends UI.Widget.VBox {
sourceTextElement.textContent = trim ? text.substr(0, MAX_LENGTH) : text;

const sourceTreeElement = new UI.TreeOutline.TreeElement(sourceTextElement);

treeElement.removeChildren();
treeElement.appendChild(sourceTreeElement);
this.addEntryContextMenuHandler(sourceTreeElement, i18nString(UIStrings.copyPayload), 'copy-payload', () => text);
if (!trim) {
return;
}
Expand Down Expand Up @@ -350,7 +355,8 @@ export class RequestPayloadView extends UI.Widget.VBox {
}

const paramTreeElement = new UI.TreeOutline.TreeElement(paramNameValue);
this.addEntryContextMenuHandler(paramTreeElement, param.value);
this.addEntryContextMenuHandler(
paramTreeElement, i18nString(UIStrings.copyValue), 'copy-value', () => decodeURIComponent(param.value));
paramsTreeElement.appendChild(paramTreeElement);
}

Expand Down
16 changes: 15 additions & 1 deletion test/e2e/network/network-request-view_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ import {
getResourcesPath,
getTextContent,
pasteText,
readClipboard,
step,
typeText,
waitFor,
waitForAria,
waitForElementWithTextContent,
waitForFunction,
} from '../../shared/helper.js';

import {CONSOLE_TAB_SELECTOR, focusConsolePrompt} from '../helpers/console-helpers.js';
import {triggerLocalFindDialog} from '../helpers/memory-helpers.js';
import {
Expand Down Expand Up @@ -487,6 +487,20 @@ describe('The Network Request view', () => {
].flat();

assertOutlineMatches(expectedPayloadContent, payloadOutlineText);

// Context menu to copy single parsed entry.
const parsedEntry = await waitForElementWithTextContent('alpha');
await parsedEntry.click({button: 'right'});
await (await waitForElementWithTextContent('Copy value')).click();
assert.strictEqual(await readClipboard(), 'alpha');

// Context menu to copy the raw payload.
const viewSource = await waitForElementWithTextContent('view source');
await viewSource.click();
const source = await waitForElementWithTextContent('id=42&param=a%20b');
await source.click({button: 'right'});
await (await waitForElementWithTextContent('Copy')).click();
assert.strictEqual(await readClipboard(), 'id=42&param=a%20b');
});

it('shows raw headers', async () => {
Expand Down
8 changes: 8 additions & 0 deletions test/shared/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -824,3 +824,11 @@ export async function raf(page: puppeteer.Page): Promise<void> {
return new Promise(resolve => window.requestAnimationFrame(resolve));
});
}

export async function readClipboard() {
const {frontend, browser} = getBrowserAndPages();
await browser.defaultBrowserContext().overridePermissions(frontend.url(), ['clipboard-read']);
const clipboard = await frontend.evaluate(async () => navigator.clipboard.readText());
await browser.defaultBrowserContext().clearPermissionOverrides();
return clipboard;
}

0 comments on commit ba3c245

Please sign in to comment.