зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1648373 - Add slow requests indicator r=Honza
Differential Revision: https://phabricator.services.mozilla.com/D81629
This commit is contained in:
Родитель
214b420d11
Коммит
7cf3a162e6
|
@ -2178,6 +2178,9 @@ pref("devtools.netmonitor.har.enableAutoExportToFile", false);
|
||||||
|
|
||||||
pref("devtools.netmonitor.features.webSockets", true);
|
pref("devtools.netmonitor.features.webSockets", true);
|
||||||
|
|
||||||
|
// netmonitor audit
|
||||||
|
pref("devtools.netmonitor.audits.slow", 500);
|
||||||
|
|
||||||
// Disable the EventSource Inspector.
|
// Disable the EventSource Inspector.
|
||||||
pref("devtools.netmonitor.features.serverSentEvents", false);
|
pref("devtools.netmonitor.features.serverSentEvents", false);
|
||||||
|
|
||||||
|
|
|
@ -143,6 +143,7 @@ class WebConsoleFront extends FrontClassWithSpec(webconsoleSpec) {
|
||||||
networkInfo.response.remoteAddress = packet.response.remoteAddress;
|
networkInfo.response.remoteAddress = packet.response.remoteAddress;
|
||||||
networkInfo.response.remotePort = packet.response.remotePort;
|
networkInfo.response.remotePort = packet.response.remotePort;
|
||||||
networkInfo.discardResponseBody = packet.response.discardResponseBody;
|
networkInfo.discardResponseBody = packet.response.discardResponseBody;
|
||||||
|
networkInfo.response.waitingTime = packet.response.waitingTime;
|
||||||
break;
|
break;
|
||||||
case "responseContent":
|
case "responseContent":
|
||||||
networkInfo.response.content = {
|
networkInfo.response.content = {
|
||||||
|
|
|
@ -238,6 +238,7 @@ devtools.jar:
|
||||||
content/netmonitor/src/assets/icons/play.svg (netmonitor/src/assets/icons/play.svg)
|
content/netmonitor/src/assets/icons/play.svg (netmonitor/src/assets/icons/play.svg)
|
||||||
content/netmonitor/src/assets/icons/arrow-up.svg (netmonitor/src/assets/icons/arrow-up.svg)
|
content/netmonitor/src/assets/icons/arrow-up.svg (netmonitor/src/assets/icons/arrow-up.svg)
|
||||||
content/netmonitor/src/assets/icons/shield.svg (netmonitor/src/assets/icons/shield.svg)
|
content/netmonitor/src/assets/icons/shield.svg (netmonitor/src/assets/icons/shield.svg)
|
||||||
|
content/netmonitor/src/assets/icons/turtle.svg (netmonitor/src/assets/icons/turtle.svg)
|
||||||
content/netmonitor/index.html (netmonitor/index.html)
|
content/netmonitor/index.html (netmonitor/index.html)
|
||||||
content/netmonitor/src/assets/styles/StatusCode.css (netmonitor/src/assets/styles/StatusCode.css)
|
content/netmonitor/src/assets/styles/StatusCode.css (netmonitor/src/assets/styles/StatusCode.css)
|
||||||
content/netmonitor/src/assets/styles/messages.css (netmonitor/src/assets/styles/messages.css)
|
content/netmonitor/src/assets/styles/messages.css (netmonitor/src/assets/styles/messages.css)
|
||||||
|
|
|
@ -1120,6 +1120,11 @@ netmonitor.timings.receive=Receiving:
|
||||||
# in the network details timings tab, with a link to external documentation
|
# in the network details timings tab, with a link to external documentation
|
||||||
netmonitor.timings.learnMore=Learn more about timings
|
netmonitor.timings.learnMore=Learn more about timings
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (netmonitor.audits.slowTooltip): This is the tooltip text displayed
|
||||||
|
# in the network request list file column, on the slow icon button.
|
||||||
|
# %1$S is the waiting time %2$S is the slow threshold.
|
||||||
|
netmonitor.audits.slowTooltip=Slow request: The server response time %1$S, is over the recommended limit of %2$S
|
||||||
|
|
||||||
# LOCALIZATION NOTE (netmonitor.security.warning.cipher): A tooltip
|
# LOCALIZATION NOTE (netmonitor.security.warning.cipher): A tooltip
|
||||||
# for warning icon that indicates a connection uses insecure cipher suite.
|
# for warning icon that indicates a connection uses insecure cipher suite.
|
||||||
netmonitor.security.warning.cipher=The cipher used for encryption is deprecated and insecure.
|
netmonitor.security.warning.cipher=The cipher used for encryption is deprecated and insecure.
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
<!-- 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/. -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 7.5" width="12" height="12" fill="context-fill">
|
||||||
|
<path d="M1.5,4.5c.75,0,1.31.75,1.68,1.49A4.47,4.47,0,0,1,7.5,2.25C10.5,2.25,12,5,12,7.5h-.75V9.38a.37.37,0,0,1-.37.38H9.38A.38.38,0,0,1,9,9.38V8.25H5.25V9.38a.37.37,0,0,1-.37.38H3.38A.37.37,0,0,1,3,9.38V7.5H1.5a1.5,1.5,0,0,1,0-3Z" transform="translate(0 -2.25)"/>
|
||||||
|
</svg>
|
После Ширина: | Высота: | Размер: 591 B |
|
@ -33,6 +33,49 @@
|
||||||
background-image: url(chrome://devtools/skin/images/profiler-stopwatch.svg);
|
background-image: url(chrome://devtools/skin/images/profiler-stopwatch.svg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.requests-list-slow-button {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
top: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
background-image: linear-gradient(to right,transparent, var(--theme-body-background) 43%);
|
||||||
|
padding-inline-end: 30px;
|
||||||
|
padding-inline-start: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.request-list-item:not(.selected).odd .requests-list-slow-button {
|
||||||
|
background-image: linear-gradient(to right,transparent, var(--table-zebra-inline-icons-background) 43%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.request-list-item:not(.selected):hover .requests-list-slow-button,
|
||||||
|
.request-list-item:not(.selected).odd:hover .requests-list-slow-button {
|
||||||
|
background-image: linear-gradient(to right,transparent, var(--table-selection-inline-icons-background-hover) 43%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.request-list-item.selected .requests-list-slow-button {
|
||||||
|
background-image: linear-gradient(to right,transparent, var(--theme-selection-background) 43%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.requests-list-slow-button::before {
|
||||||
|
content: "";
|
||||||
|
width: 12px;
|
||||||
|
height: 16px;
|
||||||
|
display: inline-block;
|
||||||
|
background-image: url(chrome://devtools/content/netmonitor/src/assets/icons/turtle.svg);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position-x: right;
|
||||||
|
padding-inline-end: 14px;
|
||||||
|
fill: var(--grey-40);
|
||||||
|
-moz-context-properties: fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
.request-list-item.selected .requests-list-slow-button::before {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
.requests-list-reload-notice-button {
|
.requests-list-reload-notice-button {
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
min-height: 26px;
|
min-height: 26px;
|
||||||
|
@ -97,6 +140,10 @@
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.requests-list-column {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.requests-list-column > * {
|
.requests-list-column > * {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
:root.theme-dark {
|
:root.theme-dark {
|
||||||
--table-splitter-color: var(--grey-70);
|
--table-splitter-color: var(--grey-70);
|
||||||
--table-zebra-background: rgba(255,255,255,0.05);
|
--table-zebra-background: rgba(255,255,255,0.05);
|
||||||
|
--table-zebra-inline-icons-background: rgb(49, 47, 47);
|
||||||
--table-selection-background-hover: rgba(53, 59, 72, 1);
|
--table-selection-background-hover: rgba(53, 59, 72, 1);
|
||||||
|
--table-selection-inline-icons-background-hover: rgba(53, 59, 72, 1);
|
||||||
|
|
||||||
--timing-blocked-color: var(--red-20);
|
--timing-blocked-color: var(--red-20);
|
||||||
--timing-dns-color: rgba(223, 128, 255, 0.8); /* pink */
|
--timing-dns-color: rgba(223, 128, 255, 0.8); /* pink */
|
||||||
|
@ -29,7 +31,9 @@
|
||||||
:root.theme-light {
|
:root.theme-light {
|
||||||
--table-splitter-color: var(--grey-20);
|
--table-splitter-color: var(--grey-20);
|
||||||
--table-zebra-background: rgba(247, 247, 247, 0.8);
|
--table-zebra-background: rgba(247, 247, 247, 0.8);
|
||||||
|
--table-zebra-inline-icons-background: rgba(247, 247, 247);
|
||||||
--table-selection-background-hover: rgba(209, 232, 255, 0.8);
|
--table-selection-background-hover: rgba(209, 232, 255, 0.8);
|
||||||
|
--table-selection-inline-icons-background-hover: rgba(209, 232, 255);
|
||||||
|
|
||||||
--timing-blocked-color: var(--red-70);
|
--timing-blocked-color: var(--red-70);
|
||||||
--timing-dns-color: rgba(223, 128, 255, 0.8); /* pink */
|
--timing-dns-color: rgba(223, 128, 255, 0.8); /* pink */
|
||||||
|
|
|
@ -8,16 +8,24 @@ const { Component } = require("devtools/client/shared/vendor/react");
|
||||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||||
const { L10N } = require("devtools/client/netmonitor/src/utils/l10n");
|
const { L10N } = require("devtools/client/netmonitor/src/utils/l10n");
|
||||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||||
|
const {
|
||||||
|
connect,
|
||||||
|
} = require("devtools/client/shared/redux/visibility-handler-connect");
|
||||||
const {
|
const {
|
||||||
propertiesEqual,
|
propertiesEqual,
|
||||||
} = require("devtools/client/netmonitor/src/utils/request-utils");
|
} = require("devtools/client/netmonitor/src/utils/request-utils");
|
||||||
|
const {
|
||||||
|
getFormattedTime,
|
||||||
|
} = require("devtools/client/netmonitor/src/utils/format-utils");
|
||||||
|
|
||||||
const UPDATED_FILE_PROPS = ["urlDetails"];
|
const UPDATED_FILE_PROPS = ["urlDetails", "waitingTime"];
|
||||||
|
|
||||||
class RequestListColumnFile extends Component {
|
class RequestListColumnFile extends Component {
|
||||||
static get propTypes() {
|
static get propTypes() {
|
||||||
return {
|
return {
|
||||||
item: PropTypes.object.isRequired,
|
item: PropTypes.object.isRequired,
|
||||||
|
slowLimit: PropTypes.number,
|
||||||
|
onWaterfallMouseDown: PropTypes.func,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +39,9 @@ class RequestListColumnFile extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
item: { urlDetails },
|
item: { urlDetails, waitingTime },
|
||||||
|
slowLimit,
|
||||||
|
onWaterfallMouseDown,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const originalFileURL = urlDetails.url;
|
const originalFileURL = urlDetails.url;
|
||||||
|
@ -50,14 +60,28 @@ class RequestListColumnFile extends Component {
|
||||||
? originalFileURL
|
? originalFileURL
|
||||||
: ORIGINAL_FILE_URL + "\n\n" + DECODED_FILE_URL;
|
: ORIGINAL_FILE_URL + "\n\n" + DECODED_FILE_URL;
|
||||||
|
|
||||||
|
const isSlow = slowLimit > 0 && !!waitingTime && waitingTime > slowLimit;
|
||||||
|
|
||||||
return dom.td(
|
return dom.td(
|
||||||
{
|
{
|
||||||
className: "requests-list-column requests-list-file",
|
className: "requests-list-column requests-list-file",
|
||||||
title: fileToolTip,
|
title: fileToolTip,
|
||||||
},
|
},
|
||||||
requestedFile
|
dom.div({}, requestedFile),
|
||||||
|
isSlow &&
|
||||||
|
dom.div({
|
||||||
|
title: L10N.getFormatStr(
|
||||||
|
"netmonitor.audits.slowTooltip",
|
||||||
|
getFormattedTime(waitingTime),
|
||||||
|
getFormattedTime(slowLimit)
|
||||||
|
),
|
||||||
|
onMouseDown: onWaterfallMouseDown,
|
||||||
|
className: "requests-list-slow-button",
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = RequestListColumnFile;
|
module.exports = connect(state => ({
|
||||||
|
slowLimit: state.ui.slowLimit,
|
||||||
|
}))(RequestListColumnFile);
|
||||||
|
|
|
@ -152,6 +152,7 @@ const UPDATED_REQ_ITEM_PROPS = [
|
||||||
"requestHeaders",
|
"requestHeaders",
|
||||||
"responseCookies",
|
"responseCookies",
|
||||||
"responseHeaders",
|
"responseHeaders",
|
||||||
|
"waitingTime",
|
||||||
];
|
];
|
||||||
|
|
||||||
const UPDATED_REQ_PROPS = [
|
const UPDATED_REQ_PROPS = [
|
||||||
|
@ -177,7 +178,11 @@ const COLUMN_COMPONENTS = [
|
||||||
ColumnComponent: RequestListColumnDomain,
|
ColumnComponent: RequestListColumnDomain,
|
||||||
props: ["onSecurityIconMouseDown"],
|
props: ["onSecurityIconMouseDown"],
|
||||||
},
|
},
|
||||||
{ column: "file", ColumnComponent: RequestListColumnFile },
|
{
|
||||||
|
column: "file",
|
||||||
|
ColumnComponent: RequestListColumnFile,
|
||||||
|
props: ["onWaterfallMouseDown"],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
column: "url",
|
column: "url",
|
||||||
ColumnComponent: RequestListColumnUrl,
|
ColumnComponent: RequestListColumnUrl,
|
||||||
|
|
|
@ -419,6 +419,7 @@ class FirefoxDataProvider {
|
||||||
status: networkInfo.response.status,
|
status: networkInfo.response.status,
|
||||||
statusText: networkInfo.response.statusText,
|
statusText: networkInfo.response.statusText,
|
||||||
headersSize: networkInfo.response.headersSize,
|
headersSize: networkInfo.response.headersSize,
|
||||||
|
waitingTime: networkInfo.response.waitingTime,
|
||||||
});
|
});
|
||||||
this.emitForTests(TEST_EVENTS.STARTED_RECEIVING_RESPONSE, actor);
|
this.emitForTests(TEST_EVENTS.STARTED_RECEIVING_RESPONSE, actor);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -226,6 +226,7 @@ const UPDATE_PROPS = [
|
||||||
"blockedReason",
|
"blockedReason",
|
||||||
"blockingExtension",
|
"blockingExtension",
|
||||||
"channelId",
|
"channelId",
|
||||||
|
"waitingTime",
|
||||||
];
|
];
|
||||||
|
|
||||||
const PANELS = {
|
const PANELS = {
|
||||||
|
|
|
@ -154,6 +154,10 @@ function getFilterState() {
|
||||||
return new FilterTypes(activeFilters);
|
return new FilterTypes(activeFilters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get json data from preferences
|
||||||
|
*/
|
||||||
|
|
||||||
function getPref(pref) {
|
function getPref(pref) {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(Services.prefs.getCharPref(pref));
|
return JSON.parse(Services.prefs.getCharPref(pref));
|
||||||
|
|
|
@ -81,6 +81,7 @@ function UI(initialState = {}) {
|
||||||
"devtools.netmonitor.persistlog"
|
"devtools.netmonitor.persistlog"
|
||||||
),
|
),
|
||||||
browserCacheDisabled: Services.prefs.getBoolPref("devtools.cache.disabled"),
|
browserCacheDisabled: Services.prefs.getBoolPref("devtools.cache.disabled"),
|
||||||
|
slowLimit: Services.prefs.getIntPref("devtools.netmonitor.audits.slow"),
|
||||||
statisticsOpen: false,
|
statisticsOpen: false,
|
||||||
waterfallWidth: null,
|
waterfallWidth: null,
|
||||||
networkActionOpen: false,
|
networkActionOpen: false,
|
||||||
|
|
|
@ -410,6 +410,7 @@ const NetworkEventActor = protocol.ActorClassWithSpec(networkEventSpec, {
|
||||||
this._response.status = info.status;
|
this._response.status = info.status;
|
||||||
this._response.statusText = info.statusText;
|
this._response.statusText = info.statusText;
|
||||||
this._response.headersSize = info.headersSize;
|
this._response.headersSize = info.headersSize;
|
||||||
|
this._response.waitingTime = info.waitingTime;
|
||||||
// Consider as not discarded if info.discardResponseBody is undefined
|
// Consider as not discarded if info.discardResponseBody is undefined
|
||||||
this._discardResponseBody = !!info.discardResponseBody;
|
this._discardResponseBody = !!info.discardResponseBody;
|
||||||
|
|
||||||
|
|
|
@ -495,6 +495,7 @@ NetworkObserver.prototype = {
|
||||||
status: response.status,
|
status: response.status,
|
||||||
statusText: response.statusText,
|
statusText: response.statusText,
|
||||||
headersSize: 0,
|
headersSize: 0,
|
||||||
|
waitingTime: 0,
|
||||||
},
|
},
|
||||||
"",
|
"",
|
||||||
true
|
true
|
||||||
|
@ -1087,7 +1088,9 @@ NetworkObserver.prototype = {
|
||||||
response.status = statusLineArray.shift();
|
response.status = statusLineArray.shift();
|
||||||
response.statusText = statusLineArray.join(" ");
|
response.statusText = statusLineArray.join(" ");
|
||||||
response.headersSize = extraStringData.length;
|
response.headersSize = extraStringData.length;
|
||||||
|
response.waitingTime = this._convertTimeToMs(
|
||||||
|
this._getWaitTiming(httpActivity.timings)
|
||||||
|
);
|
||||||
httpActivity.responseStatus = response.status;
|
httpActivity.responseStatus = response.status;
|
||||||
httpActivity.headersSize = response.headersSize;
|
httpActivity.headersSize = response.headersSize;
|
||||||
|
|
||||||
|
@ -1443,6 +1446,10 @@ NetworkObserver.prototype = {
|
||||||
return serverTimings;
|
return serverTimings;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_convertTimeToMs: function(timing) {
|
||||||
|
return Math.max(Math.round(timing / 1000), -1);
|
||||||
|
},
|
||||||
|
|
||||||
_calculateOffsetAndTotalTime: function(
|
_calculateOffsetAndTotalTime: function(
|
||||||
harTimings,
|
harTimings,
|
||||||
secureConnectionStartTime,
|
secureConnectionStartTime,
|
||||||
|
@ -1452,7 +1459,7 @@ NetworkObserver.prototype = {
|
||||||
) {
|
) {
|
||||||
let totalTime = 0;
|
let totalTime = 0;
|
||||||
for (const timing in harTimings) {
|
for (const timing in harTimings) {
|
||||||
const time = Math.max(Math.round(harTimings[timing] / 1000), -1);
|
const time = this._convertTimeToMs(harTimings[timing]);
|
||||||
harTimings[timing] = time;
|
harTimings[timing] = time;
|
||||||
if (time > -1 && timing != "connect" && timing != "ssl") {
|
if (time > -1 && timing != "connect" && timing != "ssl") {
|
||||||
totalTime += time;
|
totalTime += time;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче