Bug 1744790 - [devtools] Add new Edit and resend panel in the left side panel r=bomsy

This patch creates an HTTP Custom request component without functionality, only shows the new panel on the left. Also, it adds a simple test, that will be uptaded as new features are added.

Differential Revision: https://phabricator.services.mozilla.com/D133390
This commit is contained in:
Claudia 2021-12-15 15:59:05 +00:00
Родитель c09f207639
Коммит f90f2e8dc0
12 изменённых файлов: 500 добавлений и 8 удалений

Просмотреть файл

@ -422,6 +422,7 @@ devtools.jar:
content/netmonitor/src/assets/styles/RequestBlockingPanel.css (netmonitor/src/assets/styles/RequestBlockingPanel.css)
content/netmonitor/src/assets/styles/NetworkDetailsBar.css (netmonitor/src/assets/styles/NetworkDetailsBar.css)
content/netmonitor/src/assets/styles/CustomRequestPanel.css (netmonitor/src/assets/styles/CustomRequestPanel.css)
content/netmonitor/src/assets/styles/HTTPCustomRequestPanel.css (netmonitor/src/assets/styles/HTTPCustomRequestPanel.css)
content/netmonitor/src/assets/styles/RequestList.css (netmonitor/src/assets/styles/RequestList.css)
content/netmonitor/src/assets/styles/StatisticsPanel.css (netmonitor/src/assets/styles/StatisticsPanel.css)
content/netmonitor/src/assets/styles/StatusBar.css (netmonitor/src/assets/styles/StatusBar.css)

Просмотреть файл

@ -855,6 +855,10 @@ netmonitor.requestBlockingMenu.disableAllBlockedUrls=Disable all
# in the action bar's search tab
netmonitor.actionbar.search=Search
# LOCALIZATION NOTE (netmonitor.actionbar.HTTPCustomRequest): This is the label displayed
# in the action bar's edit and resend tab
netmonitor.actionbar.HTTPCustomRequest=New Request
# LOCALIZATION NOTE (messagesTruncated): This is the text displayed
# in the messages panel when the number of messages is over the
# truncation limit.

Просмотреть файл

@ -0,0 +1,182 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.network-monitor .http-custom-method-and-url .http-custom-method-value-label {
grid-column: 1 / 1;
grid-row: 1 / 1;
}
.network-monitor .http-custom-method-and-url .http-custom-url-value {
grid-column: 2 / 2;
grid-row: 2 / 2;
margin-inline-start: 12px;
}
.network-monitor .http-custom-method-and-url .http-custom-method-value {
grid-column: 1 / 1;
grid-row: 2 / 2;
}
.network-monitor .http-custom-method-and-url .http-custom-url-value-label {
grid-column: 2 / 2;
grid-row: 1 / 1 ;
margin-inline-start: 12px;
}
.network-monitor .tabpanel-summary-container.http-custom-method-and-url {
display: grid;
grid-template-columns: auto 1fr;
}
.network-monitor .http-custom-method-and-url input {
font-weight: 400;
margin-top: 4px;
min-width: 9ch;
padding: 2px 3px;
}
.network-monitor .http-custom-request-panel textarea {
font-weight: 400;
margin-top: 4px;
padding: 8px;
direction: ltr;
}
.network-monitor .http-custom-request-panel {
display: flex;
flex-direction: column;
height: 100%;
}
.network-monitor .http-custom-request-panel .http-custom-request-panel-content {
flex: 1 1 auto;
height: auto;
overflow: auto;
}
.network-monitor .http-custom-request-panel-content > div:not(.http-custom-request) {
margin-bottom: 12px;
padding-inline: 16px;
}
.network-monitor .http-custom-request {
display: block;
padding: 0;
}
.network-monitor .http-custom-request .http-custom-request-button-container {
display: flex;
flex-wrap: wrap-reverse;
gap: 8px;
margin-block: 16px 12px;
margin-inline: 16px;
}
.network-monitor .http-custom-request-panel .http-custom-request-label {
font-weight: 400;
white-space: nowrap;
}
.network-monitor .http-custom-request button {
height: 24px;
margin-bottom: 4px;
padding-inline: 8px;
width: auto;
}
.network-monitor .http-custom-request button:focus {
box-shadow: 0 0 0 1px #0a84ff inset, 0 0 0 1px #0a84ff,
0 0 0 4px rgba(10,132,255,0.3)
}
.network-monitor .http-custom-request #http-custom-request-send-button {
background-color: var(--blue-60);
color: white;
}
.network-monitor .http-custom-request #http-custom-request-send-button:active {
background-color: var(--blue-80);
}
.network-monitor .http-custom-request #http-custom-request-send-button:hover {
background-color: var(--blue-70);
}
.network-monitor .http-custom-request #http-custom-request-close-button {
margin-inline-end: 4px;
}
.network-monitor .http-custom-header {
border-bottom-width: 1px;
border-style: solid;
border-width: 0;
flex: none;
height: calc(var(--theme-toolbar-height) + 1px);
padding: 4px 16px;
}
:root.theme-dark .network-details-bar .http-custom-request-panel {
background-color: var(--grey-85);
}
:root.theme-dark .network-monitor #http-custom-request-close-button {
background-color: var(--toolbarbutton-background);
border: 1px solid var(--theme-splitter-color);
}
:root.theme-dark .network-monitor #http-custom-request-close-button:hover:active {
background-color: var(--theme-selection-background-hover);
}
:root.theme-dark .network-monitor #http-custom-request-close-button:focus {
background-color: var(--theme-selection-focus-background);
}
:root.theme-dark .network-monitor .http-custom-request-label.http-custom-header {
background-color: var(--grey-80);
border-bottom: 1px solid var(--theme-splitter-color);
}
:root.theme-dark .network-details-bar .http-custom-request-panel input,
:root.theme-dark .network-details-bar .http-custom-request-panel textarea {
background-color: var(--grey-70);
border: 1px solid var(--grey-85);
color: white;
}
:root.theme-dark .network-monitor .http-custom-request-label {
color: var(--grey-40);
}
:root.theme-light .network-details-bar .http-custom-request-label.http-custom-header {
background-color: var(--grey-10);
border-bottom: 1px solid var(--grey-25);
}
:root.theme-light .network-monitor #http-custom-request-close-button {
background-color: var(--grey-20);
border: var(--theme-splitter-color);
}
:root.theme-light .network-monitor #http-custom-request-close-button:hover:active {
background-color: var(--theme-selection-background-hover);
}
:root.theme-light .network-monitor #http-custom-request-close-button:focus {
outline: 2px solid var(--blue-50);
outline-offset: -2px;
box-shadow: 0 0 0 2px rgba(10, 132, 255, 0.3);
border-radius: 2px;
}
:root.theme-light .network-details-bar .http-custom-request-panel input,
:root.theme-light .network-details-bar .http-custom-request-panel textarea {
background-color: white;
border: 1px solid var(--grey-25);
color: var(--grey-90);
}
:root.theme-light .network-monitor .http-custom-request-label {
color: var(--grey-60);
}

Просмотреть файл

@ -506,12 +506,12 @@
/* Custom request panel */
.network-monitor .custom-request-panel {
.network-monitor .custom-request-panel, .http-custom-request-panel {
height: 100%;
background-color: var(--theme-sidebar-background);
}
.theme-dark .network-monitor .custom-request-panel {
.theme-dark .network-monitor .custom-request-panel, .http-custom-request-panel {
color: var(--theme-selection-color);
}
@ -519,7 +519,7 @@
font-weight: 600;
}
.network-monitor .custom-request-panel textarea {
.network-monitor .custom-request-panel, .http-custom-request-panel textarea {
resize: none;
font: message-box;
font-size: var(--theme-body-font-size);
@ -528,26 +528,34 @@
.network-monitor .custom-header,
.network-monitor .custom-method-and-url,
.network-monitor .custom-request,
.network-monitor .custom-section {
.network-monitor .custom-section,
.network-monitor .http-custom-header,
.network-monitor .http-custom-method-and-url,
.network-monitor .http-custom-request,
.network-monitor .http-custom-section {
display: flex;
}
.network-monitor .custom-header {
.network-monitor .custom-header,
.network-monitor .http-custom-header {
flex-grow: 1;
font-size: 1.1em;
padding-top: 4px;
}
.network-monitor .custom-section {
.network-monitor .custom-section,
.network-monitor .http-custom-section{
flex-direction: column;
margin-top: 0.5em;
}
.network-monitor .custom-method-value {
.network-monitor .custom-method-value,
.network-monitor .http-custom-method-value{
width: 4.5em;
}
.network-monitor .custom-url-value {
.network-monitor .custom-url-value,
.network-monitor .http-custom-url-value {
flex-grow: 1;
margin-inline-start: 6px;
}

Просмотреть файл

@ -25,6 +25,7 @@
@import "chrome://devtools/content/netmonitor/src/assets/styles/NetworkDetailsBar.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/StatisticsPanel.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/CustomRequestPanel.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/HTTPCustomRequestPanel.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/StatusCode.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/messages.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/search.css";

Просмотреть файл

@ -38,6 +38,12 @@ loader.lazyGetter(this, "RequestBlockingPanel", function() {
);
});
loader.lazyGetter(this, "HTTPCustomRequestPanel", function() {
return createFactory(
require("devtools/client/netmonitor/src/components/new-request/HTTPCustomRequestPanel")
);
});
class NetworkActionBar extends Component {
static get propTypes() {
return {
@ -63,6 +69,9 @@ class NetworkActionBar extends Component {
const showSearchPanel = Services.prefs.getBoolPref(
"devtools.netmonitor.features.search"
);
const showNewCustomRequestPanel = Services.prefs.getBoolPref(
"devtools.netmonitor.features.newEditAndResend"
);
return div(
{ className: "network-action-bar" },
@ -79,6 +88,15 @@ class NetworkActionBar extends Component {
canVerticalSplit: false,
},
},
showNewCustomRequestPanel &&
TabPanel(
{
id: PANELS.HTTP_CUSTOM_REQUEST,
title: L10N.getStr("netmonitor.actionbar.HTTPCustomRequest"),
className: "network-action-bar-HTTP-custom-request",
},
HTTPCustomRequestPanel()
),
showSearchPanel &&
TabPanel(
{

Просмотреть файл

@ -4,6 +4,7 @@
DIRS += [
"messages",
"new-request",
"previews",
"request-blocking",
"request-details",

Просмотреть файл

@ -0,0 +1,208 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { Component } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const {
connect,
} = require("devtools/client/shared/redux/visibility-handler-connect");
const { L10N } = require("devtools/client/netmonitor/src/utils/l10n");
const Actions = require("devtools/client/netmonitor/src/actions/index");
const {
getSelectedRequest,
} = require("devtools/client/netmonitor/src/selectors/index");
const {
getUrlQuery,
parseQueryString,
writeHeaderText,
} = require("devtools/client/netmonitor/src/utils/request-utils");
const { button, div, input, label, textarea } = dom;
const CUSTOM_HEADERS = L10N.getStr("netmonitor.custom.headers");
const CUSTOM_NEW_REQUEST_METHOD_LABEL = L10N.getStr(
"netmonitor.custom.newRequestMethodLabel"
);
const CUSTOM_NEW_REQUEST_URL_LABEL = L10N.getStr(
"netmonitor.custom.newRequestUrlLabel"
);
const CUSTOM_POSTDATA = L10N.getStr("netmonitor.custom.postData");
const CUSTOM_QUERY = L10N.getStr("netmonitor.custom.query");
const CUSTOM_SEND = L10N.getStr("netmonitor.custom.send");
/*
* HTTP Custom request panel component
* A network request panel which enables creating and sending new requests
* or selecting, editing and re-sending current requests.
*/
class HTTPCustomRequestPanel extends Component {
static get propTypes() {
return {
connector: PropTypes.object,
request: PropTypes.object,
sendCustomRequest: PropTypes.func.isRequired,
};
}
render() {
const { request = {}, sendCustomRequest } = this.props;
const {
method,
customQueryValue,
requestHeaders,
requestPostData,
url,
} = request;
let headers = "";
if (requestHeaders) {
headers = requestHeaders.customHeadersValue
? requestHeaders.customHeadersValue
: writeHeaderText(requestHeaders.headers).trim();
}
const queryArray = url ? parseQueryString(getUrlQuery(url)) : [];
let params = customQueryValue;
if (!params) {
params = queryArray
? queryArray.map(({ name, value }) => name + "=" + value).join("\n")
: "";
}
const postData = requestPostData?.postData.text
? requestPostData.postData.text
: "";
return div(
{ className: "http-custom-request-panel" },
div(
{ className: "http-custom-request-panel-content" },
div(
{ className: "tabpanel-summary-container http-custom-request" },
div(
{ className: "http-custom-request-button-container" },
button(
{
className: "devtools-button",
id: "http-custom-request-send-button",
onClick: sendCustomRequest,
},
CUSTOM_SEND
)
)
),
div(
{
className: "tabpanel-summary-container http-custom-method-and-url",
id: "http-custom-method-and-url",
},
label(
{
className:
"http-custom-method-value-label http-custom-request-label",
htmlFor: "http-custom-method-value",
},
CUSTOM_NEW_REQUEST_METHOD_LABEL
),
input({
className: "http-custom-method-value",
id: "http-custom-method-value",
onChange: evt => {},
onBlur: () => {},
value: method,
}),
label(
{
className:
"http-custom-url-value-label http-custom-request-label",
htmlFor: "http-custom-url-value",
},
CUSTOM_NEW_REQUEST_URL_LABEL
),
input({
className: "http-custom-url-value",
id: "http-custom-url-value",
onChange: evt => {},
value: url || "http://",
})
),
// Hide query field when there is no params
params
? div(
{
className: "tabpanel-summary-container http-custom-section",
id: "http-custom-query",
},
label(
{
className: "http-custom-request-label",
htmlFor: "http-custom-query-value",
},
CUSTOM_QUERY
),
textarea({
className: "tabpanel-summary-input",
id: "http-custom-query-value",
onChange: evt => {},
rows: 4,
value: params,
wrap: "off",
})
)
: null,
div(
{
id: "http-custom-headers",
className: "tabpanel-summary-container http-custom-section",
},
label(
{
className: "http-custom-request-label",
htmlFor: "custom-headers-value",
},
CUSTOM_HEADERS
),
textarea({
className: "tabpanel-summary-input",
id: "http-custom-headers-value",
onChange: evt => {},
rows: 8,
value: headers,
wrap: "off",
})
),
div(
{
id: "http-custom-postdata",
className: "tabpanel-summary-container http-custom-section",
},
label(
{
className: "http-custom-request-label",
htmlFor: "http-custom-postdata-value",
},
CUSTOM_POSTDATA
),
textarea({
className: "tabpanel-summary-input",
id: "http-custom-postdata-value",
onChange: evt => {},
rows: 6,
value: postData,
wrap: "off",
})
)
)
);
}
}
module.exports = connect(
state => ({ request: getSelectedRequest(state) }),
(dispatch, props) => ({
sendCustomRequest: () =>
dispatch(Actions.sendCustomRequest(props.connector)),
})
)(HTTPCustomRequestPanel);

Просмотреть файл

@ -0,0 +1,7 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
"HTTPCustomRequestPanel.js",
)

Просмотреть файл

@ -242,6 +242,7 @@ const PANELS = {
SECURITY: "security",
STACK_TRACE: "stack-trace",
TIMINGS: "timings",
HTTP_CUSTOM_REQUEST: "network-action-bar-HTTP-custom-request",
SEARCH: "network-action-bar-search",
BLOCKING: "network-action-bar-blocked",
};

Просмотреть файл

@ -197,6 +197,7 @@ skip-if = verify # Bug 1607678
[browser_net_jsonp.js]
[browser_net_large-response.js]
[browser_net_leak_on_tab_close.js]
[browser_net_new_request_panel.js]
[browser_net_open_in_debugger.js]
[browser_net_open_in_style_editor.js]
[browser_net_open_request_in_tab.js]

Просмотреть файл

@ -0,0 +1,60 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Test if the New Request panel shows in the left when the pref is true
*/
add_task(async function() {
const { monitor } = await initNetMonitor(HTTPS_CUSTOM_GET_URL, {
requestCount: 1,
});
info("Starting test... ");
const { document, store, windowRequire } = monitor.panelWin;
// Action should be processed synchronously in tests.
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
store.dispatch(Actions.batchEnable(false));
info("open the left panel");
let waitForPanels = waitForDOM(
document,
".monitor-panel .network-action-bar"
);
const respSearchButton = document.querySelector(
"#netmonitor-toolbar-container .devtools-search-icon"
);
respSearchButton.click();
await waitForPanels;
is(
!!document.querySelector("#network-action-bar-HTTP-custom-request-panel"),
false,
"The 'New Request' header should be hidden when the pref is false."
);
// Close the panel before changing pref
const closePanel = document.querySelector(
".network-action-bar .tabs-navigation .sidebar-toggle"
);
closePanel.click();
await pushPref("devtools.netmonitor.features.newEditAndResend", true);
info("open the left panel");
waitForPanels = waitForDOM(document, ".monitor-panel .network-action-bar");
respSearchButton.click();
await waitForPanels;
info("switching to new request panel");
is(
!!document.querySelector("#network-action-bar-HTTP-custom-request-panel"),
true,
"The 'New Request' header should be visible when the pref is true."
);
await teardown(monitor);
});