Bug 859044 - Add more information about request timings in the details pane. r?Honza draft
authorVangelis Katsikaros <vkatsikaros@gmail.com>
Sun, 28 May 2017 11:36:33 +0300
changeset 693301 ac265ac23ffc01e7ff5affc6eaa9412946020891
parent 693006 66f496680fae6e7d8f02bc17ff58b9234ee07c70
child 738989 debbc801549231dcad6baac536452b8e5ed29ca9
push id87750
push uservkatsikaros@gmail.com
push dateSun, 05 Nov 2017 12:07:01 +0000
reviewersHonza
bugs859044
milestone58.0a1
Bug 859044 - Add more information about request timings in the details pane. r?Honza MozReview-Commit-ID: AiLDLsMQR3v
devtools/client/locales/en-US/netmonitor.properties
devtools/client/netmonitor/src/assets/styles/netmonitor.css
devtools/client/netmonitor/src/components/TabboxPanel.js
devtools/client/netmonitor/src/components/TimingsPanel.js
--- 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;