Bug 1385350 - Add a Search on the home of about:telemetry r?chutten draft
authorflyingrub <flyinggrub@gmail.com>
Wed, 09 Aug 2017 17:53:23 +0200
changeset 648588 854228be984c6a0b5b2bee23cb4b4bc969ef7176
parent 648260 04bee69b3274bd8d5cf52d54a0a5cc14dbe8693a
child 726865 194407d37b0c477369edd6c8070fd9f1a5e9603d
push id74802
push userbmo:flyinggrub@gmail.com
push dateFri, 18 Aug 2017 00:28:51 +0000
reviewerschutten
bugs1385350
milestone57.0a1
Bug 1385350 - Add a Search on the home of about:telemetry r?chutten This allow to search in any section for data. MozReview-Commit-ID: D0aWj427Mhf
toolkit/content/aboutTelemetry.css
toolkit/content/aboutTelemetry.js
toolkit/content/aboutTelemetry.xhtml
toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
--- a/toolkit/content/aboutTelemetry.css
+++ b/toolkit/content/aboutTelemetry.css
@@ -15,16 +15,20 @@ body {
 }
 
 #categories {
   min-width: 250px;
   padding-top: 0px;
   overflow-y: auto;
 }
 
+.main-content.search > section > *:not(.data) {
+  display: none;
+}
+
 #category-raw {
   background-color: var(--in-content-page-background);
   box-sizing: border-box;
   min-width: inherit;
   position: absolute;
   bottom: 0;
   left: 0;
 }
--- a/toolkit/content/aboutTelemetry.js
+++ b/toolkit/content/aboutTelemetry.js
@@ -1384,55 +1384,78 @@ var Search = {
 
   searchHandler(e) {
     if (this.idleTimeout) {
       clearTimeout(this.idleTimeout);
     }
     this.idleTimeout = setTimeout(() => Search.search(e.target.value), FILTER_IDLE_TIMEOUT);
   },
 
-  search(text) {
-    let selectedSection = document.querySelector("section.active");
-    if (selectedSection.id === "histograms-section") {
-      let histograms = selectedSection.getElementsByClassName("histogram");
+  search(text, section = null) {
+    if (!section) {
+      let sectionId = document.querySelector(".category.selected").getAttribute("value");
+      section = document.getElementById(sectionId);
+    }
+    if (section.id === "home-section") {
+      this.homeSearch(text);
+    } else if (section.id === "histograms-section") {
+      let histograms = section.getElementsByClassName("histogram");
       this.filterElements(histograms, text);
-    } else if (selectedSection.id === "keyed-histograms-section") {
+    } else if (section.id === "keyed-histograms-section") {
       let keyedElements = [];
-      let keyedHistograms = selectedSection.getElementsByClassName("keyed-histogram");
+      let keyedHistograms = section.getElementsByClassName("keyed-histogram");
       for (let key of keyedHistograms) {
         let datas = key.getElementsByClassName("histogram");
         keyedElements.push({key, datas});
       }
       this.filterKeyedElements(keyedElements, text);
-    } else if (selectedSection.id === "keyed-scalars-section") {
+    } else if (section.id === "keyed-scalars-section") {
       let keyedElements = [];
-      let keyedScalars = selectedSection.getElementsByClassName("keyed-scalar");
+      let keyedScalars = section.getElementsByClassName("keyed-scalar");
       for (let key of keyedScalars) {
         let datas = key.querySelector("table").rows;
         keyedElements.push({key, datas});
       }
       this.filterKeyedElements(keyedElements, text);
-    } else if (selectedSection.id === "thread-hang-stats-section") {
-      let keyedElements = [];
-      let threads = selectedSection.children[0].children;
-      for (let key of threads) {
-        let datas = key.getElementsByClassName("histogram");
-        keyedElements.push({key, datas});
-      }
-      this.filterKeyedElements(keyedElements, text);
     } else {
-      let tables = selectedSection.querySelectorAll("table");
+      let tables = section.querySelectorAll("table");
       for (let table of tables) {
         let allElementsHidden = this.filterElements(table.rows, text);
         if (table.caption) {
           table.caption.hidden = allElementsHidden;
         }
       }
     }
   },
+
+  resetHome() {
+    document.getElementById("main").classList.remove("search");
+    adjustHeaderState();
+    Array.from(document.querySelectorAll("section")).forEach((section) => {
+      section.classList.toggle("active", section.id == "home-section");
+    });
+  },
+
+  homeSearch(text) {
+    if (text === "") {
+      this.resetHome();
+      return;
+    }
+    document.getElementById("main").classList.add("search");
+    let title = bundle.formatStringFromName("resultsForSearch", [text], 1);
+    adjustHeaderState(title);
+    Array.from(document.querySelectorAll("section")).forEach((section) => {
+      if (section.id == "home-section" || section.id == "raw-payload-section") {
+        section.classList.remove("active");
+        return;
+      }
+      section.classList.add("active");
+      this.search(text, section);
+    });
+  }
 }
 
 /*
  * Helper function to render JS objects with white space between top level elements
  * so that they look better in the browser
  * @param   aObject JavaScript object or array to render
  * @return  String
  */
@@ -1625,24 +1648,24 @@ var AddonDetails = {
     let addonDetails = aPing.payload.addonDetails;
     const hasData = addonDetails && Object.keys(addonDetails).length > 0;
     setHasData("addon-details-section", hasData);
     if (!hasData) {
       return;
     }
 
     for (let provider in addonDetails) {
-      let providerSection = document.createElement("h2");
+      let providerSection = document.createElement("caption");
       let titleText = bundle.formatStringFromName("addonProvider", [provider], 1);
       providerSection.appendChild(document.createTextNode(titleText));
-      addonSection.appendChild(providerSection);
 
       let headingStrings = [this.tableIDTitle, this.tableDetailsTitle ]
       let table = GenericTable.render(explodeObject(addonDetails[provider]),
                                       headingStrings);
+      table.appendChild(providerSection);
       addonSection.appendChild(table);
     }
   },
 };
 
 var Scalars = {
   /**
    * Render the scalar data - if present - from the payload in a simple key-value table.
@@ -1805,37 +1828,44 @@ function displayProcessesSelector(select
     "keyed-histograms-section",
     "events-section"
   ];
   let processes = document.getElementById("processes");
   processes.hidden = !whitelist.includes(selectedSection);
 }
 
 function adjustSearchState() {
-  let selectedSection = document.querySelector("section.active").id;
+  let selectedSection = document.querySelector(".category.selected").getAttribute("value");
   let blacklist = [
-    "home-section",
     "raw-payload-section"
   ];
-  // TODO: Implement global search for the Home section
   let search = document.getElementById("search");
   search.hidden = blacklist.includes(selectedSection);
   // Filter element on section change.
   if (!blacklist.includes(selectedSection)) {
     Search.search(search.value);
   }
 }
 
 function adjustSection() {
   let selectedCategory = document.querySelector(".category.selected");
   if (!selectedCategory.classList.contains("has-data")) {
     PingPicker._showStructuredPingData();
   }
 }
 
+function adjustHeaderState(title = null) {
+  let selected = document.querySelector(".category.selected .category-name");
+  let selectedTitle = selected.textContent.trim();
+  document.getElementById("sectionTitle").textContent = title ? title : selectedTitle;
+  let search = document.getElementById("search");
+  let placeholder = bundle.formatStringFromName("filterPlaceholder", [ selectedTitle ], 1);
+  search.setAttribute("placeholder", placeholder);
+}
+
 /**
  * Change the url according to the current section displayed
  * e.g about:telemetry#general-data
  */
 function changeUrlPath(selectedSection, subSection) {
   if (subSection) {
     let hash = window.location.hash.split("_")[0] + "_" + selectedSection;
     window.location.hash = hash;
@@ -1849,46 +1879,44 @@ function changeUrlPath(selectedSection, 
  */
 function show(selected) {
   let selectedValue = selected.getAttribute("value");
   if (selectedValue === "raw-json-viewer") {
     openJsonInFirefoxJsonViewer(JSON.stringify(gPingData, null, 2));
     return;
   }
 
-  let current_button = document.querySelector(".category.selected");
-  current_button.classList.remove("selected");
-  if (current_button.classList.contains("has-subsection")) {
-    for (let subsection of current_button.children) {
+  let selected_section = document.getElementById(selectedValue);
+  let subsections = selected_section.querySelectorAll(".sub-section");
+  if (selected.classList.contains("has-subsection")) {
+    for (let subsection of selected.children) {
       subsection.classList.remove("selected");
     }
   }
-  selected.classList.add("selected");
-  // Hack because subsection text appear selected. See Bug 1375114.
-  document.getSelection().empty();
-
-  let current_section = document.querySelector("section.active");
-  let selected_section = document.getElementById(selectedValue);
-  let subsections = current_section.querySelectorAll(".sub-section");
   if (subsections) {
     for (let subsection of subsections) {
       subsection.hidden = false;
     }
   }
-  if (current_section == selected_section)
+
+  let current_button = document.querySelector(".category.selected");
+  if (current_button == selected)
     return;
-  current_section.classList.remove("active");
+  current_button.classList.remove("selected");
+  selected.classList.add("selected");
+
+  document.querySelectorAll("section").forEach((section) => {
+    section.classList.remove("active")
+  });
   selected_section.classList.add("active");
 
-  let title = selected.querySelector(".category-name").textContent.trim();
-  document.getElementById("sectionTitle").textContent = title;
+  // Hack because subsection text appear selected. See Bug 1375114.
+  document.getSelection().empty();
 
-  let search = document.getElementById("search");
-  let placeholder = bundle.formatStringFromName("filterPlaceholder", [ title ], 1);
-  search.setAttribute("placeholder", placeholder);
+  adjustHeaderState();
   displayProcessesSelector(selectedValue);
   adjustSearchState();
   changeUrlPath(selectedValue);
 }
 
 function showSubSection(selected) {
   let current_selection = document.querySelector(".category-subsection.selected");
   if (current_selection)
@@ -2030,16 +2058,18 @@ function onLoad() {
   setupPageHeader();
 
   // Set up event listeners
   setupListeners();
 
   // Render settings.
   Settings.render();
 
+  adjustHeaderState();
+
   // Update ping data when async Telemetry init is finished.
   Telemetry.asyncFetchTelemetryData(async () => {
     await PingPicker.update();
     urlStateRestore();
   });
 }
 
 var LateWritesSingleton = {
--- a/toolkit/content/aboutTelemetry.xhtml
+++ b/toolkit/content/aboutTelemetry.xhtml
@@ -84,17 +84,17 @@
       <div class="category has-data" value="raw-payload-section">
         <span class="category-name">&aboutTelemetry.rawPayloadSection;</span>
       </div>
       <div id="category-raw" class="category has-data" value="raw-json-viewer">
           <span class="category-name">&aboutTelemetry.raw;</span>
       </div>
     </div>
 
-    <div class="main-content">
+    <div id="main" class="main-content">
 
       <div id="ping-picker" class="hidden">
         <div id="ping-source-picker">
           <h4 class="title">&aboutTelemetry.pingDataSource;</h4>
           <div>
             <input type="radio" id="ping-source-current" name="choose-ping-source" value="current" checked="checked" />
             &aboutTelemetry.showCurrentPingData;
           </div>
@@ -129,17 +129,17 @@
           <select id="choose-payload"></select>
         </div>
       </div>
 
       <div class="header">
           <div id="sectionTitle" class="header-name">
               &aboutTelemetry.pageTitle;
           </div>
-          <input type="text" id="search" placeholder="" hidden="true"/>
+          <input type="text" id="search" placeholder=""/>
           <select id="processes" hidden="true"></select>
       </div>
 
       <section id="home-section" class="active">
         <h3 id="page-subtitle"></h3>
         <p id="home-explanation"></p>
         <p id="ping-explanation"></p>
       </section>
@@ -185,19 +185,18 @@
         <div id="simple-measurements" class="data"></div>
       </section>
 
       <section id="telemetry-log-section">
         <div id="telemetry-log" class="data"></div>
       </section>
 
       <section id="slow-sql-section">
-        <div id="slow-sql-tables" class="data">
-          <p id="sql-warning" class="hidden">&aboutTelemetry.fullSqlWarning;</p>
-        </div>
+        <p id="sql-warning" class="hidden">&aboutTelemetry.fullSqlWarning;</p>
+        <div id="slow-sql-tables" class="data"></div>
       </section>
 
       <section id="chrome-hangs-section">
         <a id="chrome-hangs-fetch-symbols" href="">&aboutTelemetry.fetchStackSymbols;</a>
         <a id="chrome-hangs-hide-symbols" class="hidden" href="">&aboutTelemetry.hideStackSymbols;</a>
         <div id="chrome-hangs" class="data"></div>
       </section>
 
--- a/toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
+++ b/toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
@@ -37,16 +37,20 @@ extendedTelemetryEnabled = enabled
 
 extendedTelemetryDisabled = disabled
 
 currentPing = current
 
 # Used as a tooltip for the "current" ping title in the sidebar
 currentPingSidebar = current ping
 
+# Note to translators:
+# - %1$S will be replaced by the current text in the search input
+resultsForSearch = Results for ā€œ%1$Sā€
+
 telemetryPingTypeAll = all
 
 telemetryLogTitle = Telemetry Log
 
 telemetryLogHeadingId = Id
 
 telemetryLogHeadingTimestamp = Timestamp