Bug 859044 - Add more information about request timings in the details pane. r?Honza
MozReview-Commit-ID: AiLDLsMQR3v
--- a/devtools/client/locales/en-US/netmonitor.properties
+++ b/devtools/client/locales/en-US/netmonitor.properties
@@ -753,16 +753,21 @@ netmonitor.timings.send=Sending:
# in a "wait" state.
netmonitor.timings.wait=Waiting:
# LOCALIZATION NOTE (netmonitor.timings.receive): This is the label displayed
# in the network details timings tab identifying the amount of time spent
# in a "receive" state.
netmonitor.timings.receive=Receiving:
+# LOCALIZATION NOTE (netmonitor.timings.startedAt): This is the label displayed
+# in the network details timings tab identifying when the current request started
+# compared to the first request
+netmonitor.timings.startedAt=Started at:
+
# LOCALIZATION NOTE (netmonitor.security.warning.cipher): A tooltip
# for warning icon that indicates a connection uses insecure cipher suite.
netmonitor.security.warning.cipher=The cipher used for encryption is deprecated and insecure.
# LOCALIZATION NOTE (netmonitor.security.error): This is the label displayed
# in the security tab if a security error prevented the connection.
netmonitor.security.error=An error occured:
--- a/devtools/client/netmonitor/src/assets/styles/netmonitor.css
+++ b/devtools/client/netmonitor/src/assets/styles/netmonitor.css
@@ -1056,24 +1056,33 @@ body,
border: 1px dashed GrayText;
margin-bottom: 10px;
max-width: 300px;
max-height: 100px;
}
/* Timings tabpanel */
+.timings-area-container:not(:last-of-type) {
+ margin-bottom: 10px;
+}
+
.timings-container {
display: flex;
}
.timings-label {
width: 10em;
}
+.timings-marker-label {
+ white-space: nowrap;
+ width: 15em;
+}
+
.requests-list-timings-container {
display: flex;
flex: 1;
align-items: center;
}
.requests-list-timings-offset {
transition: width 0.2s ease-out;
--- a/devtools/client/netmonitor/src/components/TabboxPanel.js
+++ b/devtools/client/netmonitor/src/components/TabboxPanel.js
@@ -6,16 +6,17 @@
const {
createFactory,
PropTypes,
} = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { L10N } = require("../utils/l10n");
const { PANELS } = require("../constants");
+const { getDisplayedTimingMarker } = require("../selectors/index");
// Components
const Tabbar = createFactory(require("devtools/client/shared/components/tabs/TabBar"));
const TabPanel = createFactory(require("devtools/client/shared/components/tabs/Tabs").TabPanel);
const CookiesPanel = createFactory(require("./CookiesPanel"));
const HeadersPanel = createFactory(require("./HeadersPanel"));
const ParamsPanel = createFactory(require("./ParamsPanel"));
const ResponsePanel = createFactory(require("./ResponsePanel"));
@@ -34,20 +35,22 @@ const TIMINGS_TITLE = L10N.getStr("netmo
/**
* Tabbox panel component
* Display the network request details
*/
function TabboxPanel({
activeTabId,
cloneSelectedRequest = () => {},
connector,
+ firstRequestStartedMillis,
openLink,
request,
selectTab,
sourceMapService,
+ timingMarkers,
}) {
if (!request) {
return null;
}
return (
Tabbar({
activeTabId,
@@ -79,17 +82,17 @@ function TabboxPanel({
title: RESPONSE_TITLE,
},
ResponsePanel({ request, openLink }),
),
TabPanel({
id: PANELS.TIMINGS,
title: TIMINGS_TITLE,
},
- TimingsPanel({ request }),
+ TimingsPanel({ request, firstRequestStartedMillis, timingMarkers }),
),
request.cause && request.cause.stacktrace && request.cause.stacktrace.length > 0 &&
TabPanel({
id: PANELS.STACK_TRACE,
title: STACK_TRACE_TITLE,
},
StackTracePanel({ connector, openLink, request, sourceMapService }),
),
@@ -105,15 +108,26 @@ function TabboxPanel({
}
TabboxPanel.displayName = "TabboxPanel";
TabboxPanel.propTypes = {
activeTabId: PropTypes.string,
cloneSelectedRequest: PropTypes.func,
connector: PropTypes.object.isRequired,
+ firstRequestStartedMillis: PropTypes.number.isRequired,
openLink: PropTypes.func,
request: PropTypes.object,
selectTab: PropTypes.func.isRequired,
sourceMapService: PropTypes.object,
+ timingMarkers: PropTypes.object.isRequired,
};
-module.exports = connect()(TabboxPanel);
+module.exports = connect(
+ (state) => ({
+ firstRequestStartedMillis: state.requests.firstStartedMillis,
+ timingMarkers: {
+ DOMContentLoaded:
+ getDisplayedTimingMarker(state, "firstDocumentDOMContentLoadedTimestamp"),
+ load: getDisplayedTimingMarker(state, "firstDocumentLoadTimestamp"),
+ }
+ }),
+)(TabboxPanel);
--- a/devtools/client/netmonitor/src/components/TimingsPanel.js
+++ b/devtools/client/netmonitor/src/components/TimingsPanel.js
@@ -1,30 +1,36 @@
/* 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 { DOM, PropTypes } = require("devtools/client/shared/vendor/react");
+const { getFormattedTime } = require("../utils/format-utils");
const { L10N } = require("../utils/l10n");
const { getNetMonitorTimingsURL } = require("../utils/mdn-utils");
+const { getStartTime } = require("../utils/request-utils");
// Components
const MDNLink = require("./MdnLink");
const { div, span } = DOM;
const types = ["blocked", "dns", "connect", "ssl", "send", "wait", "receive"];
const TIMINGS_END_PADDING = "80px";
/*
* Timings panel component
* Display timeline bars that shows the total wait time for various stages
*/
-function TimingsPanel({ request }) {
+function TimingsPanel({
+ firstRequestStartedMillis,
+ request,
+ timingMarkers,
+}) {
if (!request.eventTimings) {
return null;
}
const { timings, totalTime, offsets } = request.eventTimings;
const timelines = types.map((type, idx) => {
// Determine the relative offset for each timings box. For example, the
// offset of third timings box will be 0 + blocked offset + dns offset
@@ -57,23 +63,57 @@ function TimingsPanel({ request }) {
L10N.getFormatStr("networkMenu.totalMS", timings[type])
)
),
);
});
return (
div({ className: "panel-container" },
- timelines,
- MDNLink({
- url: getNetMonitorTimingsURL(),
- }),
+ div({ className: "tabpanel-summary-container timings-area-container" },
+ div({ className: "tabpanel-summary-container timings-container" },
+ div({ className: "tabpanel-summary-label timings-marker-label" },
+ L10N.getStr("netmonitor.timings.startedAt"),
+ span({ className: "requests-list-timings-total" },
+ getFormattedTime(getStartTime(request, firstRequestStartedMillis))
+ ),
+ ),
+ ),
+ div({ className: "tabpanel-summary-container timings-container" },
+ div({ className: "tabpanel-summary-label timings-marker-label" },
+ "DOMContentLoaded:",
+ span({ className: "requests-list-timings-total" },
+ getFormattedTime(timingMarkers.DOMContentLoaded)
+ ),
+ ),
+ ),
+ div({ className: "tabpanel-summary-container timings-container" },
+ div({ className: "tabpanel-summary-label timings-marker-label" },
+ "load:",
+ span({ className: "requests-list-timings-total" },
+ getFormattedTime(timingMarkers.load)
+ )
+ ),
+ )
+ ),
+ div({ className: "tabpanel-summary-container timings-area-container" },
+ timelines,
+ ),
+ div({ className: "tabpanel-summary-container timings-area-container" },
+ MDNLink({
+ url: getNetMonitorTimingsURL(),
+ }),
+ ),
)
);
}
TimingsPanel.displayName = "TimingsPanel";
TimingsPanel.propTypes = {
+ // First request timings to calculate the relative timings
+ firstRequestStartedMillis: PropTypes.number.isRequired,
request: PropTypes.object.isRequired,
+ // Request's timings to calculate the relative timings
+ timingMarkers: PropTypes.object.isRequired,
};
module.exports = TimingsPanel;