Bug 1317646 - Netmonitor: move code for formatting request timings and content sizes to format-utils.js, r?jsnajdr draft
authorsteveck-chung <schung@mozilla.com>
Fri, 13 Jan 2017 16:08:22 +0800
changeset 460621 28d5ffbaca6d3fa7f060bddfc48bf2945b740fd0
parent 460419 b1c31c4a0a678194931779e0f13fba7b508eb109
child 542082 6c4393426ff139887658c1a61af6b721d197f1d4
push id41428
push userbmo:schung@mozilla.com
push dateFri, 13 Jan 2017 10:04:10 +0000
reviewersjsnajdr
bugs1317646
milestone53.0a1
Bug 1317646 - Netmonitor: move code for formatting request timings and content sizes to format-utils.js, r?jsnajdr MozReview-Commit-ID: 3PaUca62s9W
devtools/client/netmonitor/components/request-list-header.js
devtools/client/netmonitor/components/summary-button.js
devtools/client/netmonitor/constants.js
devtools/client/netmonitor/statistics-view.js
devtools/client/netmonitor/utils/format-utils.js
--- a/devtools/client/netmonitor/components/request-list-header.js
+++ b/devtools/client/netmonitor/components/request-list-header.js
@@ -9,24 +9,23 @@
 const { createClass, PropTypes, DOM } = require("devtools/client/shared/vendor/react");
 const { div, button } = DOM;
 const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const { L10N } = require("../l10n");
 const { getWaterfallScale } = require("../selectors/index");
 const Actions = require("../actions/index");
 const WaterfallBackground = require("../waterfall-background");
+const { getFormattedTime } = require("../utils/format-utils");
 
 // ms
 const REQUESTS_WATERFALL_HEADER_TICKS_MULTIPLE = 5;
 // px
 const REQUESTS_WATERFALL_HEADER_TICKS_SPACING_MIN = 60;
 
-const REQUEST_TIME_DECIMALS = 2;
-
 const HEADERS = [
   { name: "status", label: "status3" },
   { name: "method" },
   { name: "file", boxName: "icon-and-file" },
   { name: "domain", boxName: "security-and-domain" },
   { name: "cause" },
   { name: "type" },
   { name: "transferred" },
@@ -134,37 +133,26 @@ function waterfallDivisionLabels(waterfa
   // Ignore any divisions that would end up being too close to each other.
   while (scaledStep < REQUESTS_WATERFALL_HEADER_TICKS_SPACING_MIN) {
     scaledStep *= 2;
   }
 
   // Insert one label for each division on the current scale.
   for (let x = 0; x < waterfallWidth; x += scaledStep) {
     let millisecondTime = x / scale;
-
-    let normalizedTime = millisecondTime;
     let divisionScale = "millisecond";
 
     // If the division is greater than 1 minute.
-    if (normalizedTime > 60000) {
-      normalizedTime /= 60000;
+    if (millisecondTime > 60000) {
       divisionScale = "minute";
-    } else if (normalizedTime > 1000) {
+    } else if (millisecondTime > 1000) {
       // If the division is greater than 1 second.
-      normalizedTime /= 1000;
       divisionScale = "second";
     }
 
-    // Showing too many decimals is bad UX.
-    if (divisionScale == "millisecond") {
-      normalizedTime |= 0;
-    } else {
-      normalizedTime = L10N.numberWithDecimals(normalizedTime, REQUEST_TIME_DECIMALS);
-    }
-
     let width = (x + scaledStep | 0) - (x | 0);
     // Adjust the first marker for the borders
     if (x == 0) {
       width -= 2;
     }
     // Last marker doesn't need a width specified at all
     if (x + scaledStep >= waterfallWidth) {
       width = undefined;
@@ -172,17 +160,17 @@ function waterfallDivisionLabels(waterfa
 
     labels.push(div(
       {
         key: labels.length,
         className: "requests-menu-timings-division",
         "data-division-scale": divisionScale,
         style: { width }
       },
-      L10N.getFormatStr("networkMenu." + divisionScale, normalizedTime)
+      getFormattedTime(millisecondTime)
     ));
   }
 
   return labels;
 }
 
 function WaterfallLabel(waterfallWidth, scale, label) {
   let className = "button-text requests-menu-waterfall-label-wrapper";
--- a/devtools/client/netmonitor/components/summary-button.js
+++ b/devtools/client/netmonitor/components/summary-button.js
@@ -1,37 +1,37 @@
 /* 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 {
-  CONTENT_SIZE_DECIMALS,
-  REQUEST_TIME_DECIMALS,
-} = require("../constants");
 const { DOM, PropTypes } = require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const { PluralForm } = require("devtools/shared/plural-form");
 const { L10N } = require("../l10n");
 const { getDisplayedRequestsSummary } = require("../selectors/index");
 const Actions = require("../actions/index");
+const {
+  getSizeWithDecimals,
+  getTimeWithDecimals,
+} = require("../utils/format-utils");
 
 const { button, span } = DOM;
 
 function SummaryButton({
   summary,
   triggerSummary,
 }) {
   let { count, bytes, millis } = summary;
   const text = (count === 0) ? L10N.getStr("networkMenu.empty") :
     PluralForm.get(count, L10N.getStr("networkMenu.summary"))
     .replace("#1", count)
-    .replace("#2", L10N.numberWithDecimals(bytes / 1024, CONTENT_SIZE_DECIMALS))
-    .replace("#3", L10N.numberWithDecimals(millis / 1000, REQUEST_TIME_DECIMALS));
+    .replace("#2", getSizeWithDecimals(bytes / 1024))
+    .replace("#3", getTimeWithDecimals(millis / 1000));
 
   return button({
     id: "requests-menu-network-summary-button",
     className: "devtools-button",
     title: count ? text : L10N.getStr("netmonitor.toolbar.perf"),
     onClick: triggerSummary,
   },
   span({ className: "summary-info-icon" }),
--- a/devtools/client/netmonitor/constants.js
+++ b/devtools/client/netmonitor/constants.js
@@ -1,18 +1,16 @@
 /* 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 general = {
-  CONTENT_SIZE_DECIMALS: 2,
   FILTER_SEARCH_DELAY: 200,
-  REQUEST_TIME_DECIMALS: 2,
   // 100 KB in bytes
   SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE: 102400,
 };
 
 const actionTypes = {
   ADD_REQUEST: "ADD_REQUEST",
   ADD_TIMING_MARKER: "ADD_TIMING_MARKER",
   BATCH_ACTIONS: "BATCH_ACTIONS",
--- a/devtools/client/netmonitor/statistics-view.js
+++ b/devtools/client/netmonitor/statistics-view.js
@@ -11,19 +11,20 @@ const { PluralForm } = require("devtools
 const { Filters } = require("./filter-predicates");
 const { L10N } = require("./l10n");
 const { EVENTS } = require("./events");
 const { DOM } = require("devtools/client/shared/vendor/react");
 const { button } = DOM;
 const ReactDOM = require("devtools/client/shared/vendor/react-dom");
 const Actions = require("./actions/index");
 const { Chart } = require("devtools/client/shared/widgets/Chart");
-
-const REQUEST_TIME_DECIMALS = 2;
-const CONTENT_SIZE_DECIMALS = 2;
+const {
+  getSizeWithDecimals,
+  getTimeWithDecimals
+} = require("./utils/format-utils");
 
 // px
 const NETWORK_ANALYSIS_PIE_CHART_DIAMETER = 200;
 
 /**
  * Functions handling the performance statistics view.
  */
 function StatisticsView() {
@@ -109,32 +110,32 @@ StatisticsView.prototype = {
   },
 
   /**
    * Common stringifier predicates used for items and totals in both the
    * "primed" and "empty" cache charts.
    */
   _commonChartStrings: {
     size: value => {
-      let string = L10N.numberWithDecimals(value / 1024, CONTENT_SIZE_DECIMALS);
+      let string = getSizeWithDecimals(value / 1024);
       return L10N.getFormatStr("charts.sizeKB", string);
     },
     time: value => {
-      let string = L10N.numberWithDecimals(value / 1000, REQUEST_TIME_DECIMALS);
+      let string = getTimeWithDecimals(value / 1000);
       return L10N.getFormatStr("charts.totalS", string);
     }
   },
   _commonChartTotals: {
     size: total => {
-      let string = L10N.numberWithDecimals(total / 1024, CONTENT_SIZE_DECIMALS);
+      let string = getSizeWithDecimals(total / 1024);
       return L10N.getFormatStr("charts.totalSize", string);
     },
     time: total => {
       let seconds = total / 1000;
-      let string = L10N.numberWithDecimals(seconds, REQUEST_TIME_DECIMALS);
+      let string = getTimeWithDecimals(seconds);
       return PluralForm.get(seconds,
         L10N.getStr("charts.totalSeconds")).replace("#1", string);
     },
     cached: total => {
       return L10N.getFormatStr("charts.totalCached", total);
     },
     count: total => {
       return L10N.getFormatStr("charts.totalCount", total);
--- a/devtools/client/netmonitor/utils/format-utils.js
+++ b/devtools/client/netmonitor/utils/format-utils.js
@@ -9,35 +9,64 @@ const { L10N } = require("../l10n");
 // Constants for formatting bytes.
 const BYTES_IN_KB = 1024;
 const BYTES_IN_MB = Math.pow(BYTES_IN_KB, 2);
 const BYTES_IN_GB = Math.pow(BYTES_IN_KB, 3);
 const MAX_BYTES_SIZE = 1000;
 const MAX_KB_SIZE = 1000 * BYTES_IN_KB;
 const MAX_MB_SIZE = 1000 * BYTES_IN_MB;
 
+// Constants for formatting time.
+const MAX_MILLISECOND = 1000;
+const MAX_SECOND = 60 * MAX_MILLISECOND;
+
+const CONTENT_SIZE_DECIMALS = 2;
+const REQUEST_TIME_DECIMALS = 2;
+
+function getSizeWithDecimals(size, decimals = REQUEST_TIME_DECIMALS) {
+  return L10N.numberWithDecimals(size, CONTENT_SIZE_DECIMALS);
+}
+
+function getTimeWithDecimals(time) {
+  return L10N.numberWithDecimals(time, REQUEST_TIME_DECIMALS);
+}
+
 /**
  * Get a human-readable string from a number of bytes, with the B, KB, MB, or
  * GB value. Note that the transition between abbreviations is by 1000 rather
  * than 1024 in order to keep the displayed digits smaller as "1016 KB" is
  * more awkward than 0.99 MB"
  */
-function getFormattedSize(bytes, decimals = 2) {
+function getFormattedSize(bytes, decimals = REQUEST_TIME_DECIMALS) {
   if (bytes < MAX_BYTES_SIZE) {
     return L10N.getFormatStr("networkMenu.sizeB", bytes);
   } else if (bytes < MAX_KB_SIZE) {
     let kb = bytes / BYTES_IN_KB;
-    let size = L10N.numberWithDecimals(kb, decimals);
-    return L10N.getFormatStr("networkMenu.sizeKB", size);
+    return L10N.getFormatStr("networkMenu.sizeKB", getSizeWithDecimals(kb, decimals));
   } else if (bytes < MAX_MB_SIZE) {
     let mb = bytes / BYTES_IN_MB;
-    let size = L10N.numberWithDecimals(mb, decimals);
-    return L10N.getFormatStr("networkMenu.sizeMB", size);
+    return L10N.getFormatStr("networkMenu.sizeMB", getSizeWithDecimals(mb, decimals));
   }
   let gb = bytes / BYTES_IN_GB;
-  let size = L10N.numberWithDecimals(gb, decimals);
-  return L10N.getFormatStr("networkMenu.sizeGB", size);
+  return L10N.getFormatStr("networkMenu.sizeGB", getSizeWithDecimals(gb, decimals));
+}
+
+/**
+ * Get a human-readable string from a number of time, with the ms, s, or min
+ * value.
+ */
+function getFormattedTime(ms) {
+  if (ms < MAX_MILLISECOND) {
+    return L10N.getFormatStr("networkMenu.millisecond", ms | 0);
+  } else if (ms < MAX_SECOND) {
+    let sec = ms / MAX_MILLISECOND;
+    return L10N.getFormatStr("networkMenu.second", getTimeWithDecimals(sec));
+  }
+  let min = ms / MAX_SECOND;
+  return L10N.getFormatStr("networkMenu.minute", getTimeWithDecimals(min));
 }
 
 module.exports = {
   getFormattedSize,
+  getFormattedTime,
+  getSizeWithDecimals,
+  getTimeWithDecimals,
 };
-