Bug 1393478 - Display when no results are available in about:telemetry r?chutten
Also keep the search state when changing ping.
MozReview-Commit-ID: 9M2hz7ttl8e
--- a/toolkit/content/aboutTelemetry.css
+++ b/toolkit/content/aboutTelemetry.css
@@ -148,16 +148,37 @@ section:not(.active) {
}
#ping-explanation > span {
cursor: pointer;
border-bottom-width: 2px;
border-bottom-style: solid;
}
+#no-search-results {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%,-50%);
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+}
+
+#no-search-results-text {
+ font-size: 17px;
+ margin-bottom: 2em;
+}
+
+.no-search-results-image {
+ background-image: url("chrome://browser/skin/preferences/in-content-new/no-search-results.svg");
+ width: 380px;
+ height: 293px;
+}
+
.hidden {
display: none !important;
}
#ping-picker {
min-width: 300px;
position: fixed;
z-index: 2;
--- a/toolkit/content/aboutTelemetry.js
+++ b/toolkit/content/aboutTelemetry.js
@@ -1365,108 +1365,141 @@ var Search = {
allElementHidden = false;
}
}
return allElementHidden;
},
filterKeyedElements(keyedElements, filterText) {
let [isPassFunc, filter] = this.chooseFilter(filterText);
+ let allElementsHidden = true;
let needLowerCase = (isPassFunc === this.isPassText);
keyedElements.forEach((keyedElement) => {
let subject = needLowerCase ? keyedElement.key.id.toLowerCase() : keyedElement.key.id;
if (!isPassFunc(subject, filter)) { // If the keyedHistogram's name is not matched
- let allElementHidden = true;
+ let allKeyedElementsHidden = true;
for (let element of keyedElement.datas) {
let subject = needLowerCase ? element.id.toLowerCase() : element.id;
let match = isPassFunc(subject, filter);
element.hidden = !match;
if (match) {
- allElementHidden = false;
+ allKeyedElementsHidden = false;
}
}
- keyedElement.key.hidden = allElementHidden;
+ if (allElementsHidden && !allKeyedElementsHidden) {
+ allElementsHidden = false;
+ }
+ keyedElement.key.hidden = allKeyedElementsHidden;
} else { // If the keyedHistogram's name is matched
+ allElementsHidden = false;
keyedElement.key.hidden = false;
for (let element of keyedElement.datas) {
element.hidden = false;
}
}
});
+ return allElementsHidden;
},
searchHandler(e) {
if (this.idleTimeout) {
clearTimeout(this.idleTimeout);
}
this.idleTimeout = setTimeout(() => Search.search(e.target.value), FILTER_IDLE_TIMEOUT);
},
- search(text, section = null) {
+ search(text, sectionParam = null) {
+ let section = sectionParam;
if (!section) {
let sectionId = document.querySelector(".category.selected").getAttribute("value");
section = document.getElementById(sectionId);
}
+ let noSearchResults = true;
if (section.id === "home-section") {
- this.homeSearch(text);
+ return this.homeSearch(text);
} else if (section.id === "histograms-section") {
let histograms = section.getElementsByClassName("histogram");
- this.filterElements(histograms, text);
+ noSearchResults = this.filterElements(histograms, text);
} else if (section.id === "keyed-histograms-section") {
let keyedElements = [];
let keyedHistograms = section.getElementsByClassName("keyed-histogram");
for (let key of keyedHistograms) {
let datas = key.getElementsByClassName("histogram");
keyedElements.push({key, datas});
}
- this.filterKeyedElements(keyedElements, text);
+ noSearchResults = this.filterKeyedElements(keyedElements, text);
} else if (section.id === "keyed-scalars-section") {
let keyedElements = [];
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);
+ noSearchResults = this.filterKeyedElements(keyedElements, text);
} else {
let tables = section.querySelectorAll("table");
for (let table of tables) {
- let allElementsHidden = this.filterElements(table.rows, text);
+ noSearchResults = this.filterElements(table.rows, text);
if (table.caption) {
- table.caption.hidden = allElementsHidden;
+ table.caption.hidden = noSearchResults;
}
}
}
+
+ if (!sectionParam) { // If we are not searching in all section.
+ this.updateNoResults(text, noSearchResults);
+ }
+ return noSearchResults;
+ },
+
+ updateNoResults(text, noSearchResults) {
+ document.getElementById("no-search-results").classList.toggle("hidden", !noSearchResults);
+ if (noSearchResults) {
+ let section = document.querySelector(".category.selected > span");
+ let selectedTitle = section.textContent.trim();
+ if (section.parentElement.id === "category-home") {
+ selectedTitle = bundle.GetStringFromName("allSections");
+ }
+ let format = [selectedTitle, text];
+ let searchStatus = bundle.formatStringFromName("noSearchResults", format, 2);
+ document.getElementById("no-search-results-text").textContent = searchStatus;
+ }
},
resetHome() {
document.getElementById("main").classList.remove("search");
+ document.getElementById("no-search-results").classList.add("hidden");
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);
+ let noSearchResults = true;
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);
+ let sectionHidden = this.search(text, section);
+ if (noSearchResults && !sectionHidden) {
+ noSearchResults = false;
+ }
});
+ this.updateNoResults(text, noSearchResults);
}
}
/*
* 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
@@ -1852,16 +1885,17 @@ function refreshSearch() {
Search.search(search.value);
}
}
function adjustSearchState() {
let selectedSection = document.querySelector(".category.selected").getAttribute("value");
let search = document.getElementById("search");
search.hidden = Search.blacklist.includes(selectedSection);
+ document.getElementById("no-search-results").classList.add("hidden");
Search.search(""); // reinitialize search state.
}
function adjustSection() {
let selectedCategory = document.querySelector(".category.selected");
if (!selectedCategory.classList.contains("has-data")) {
PingPicker._showStructuredPingData();
}
--- a/toolkit/content/aboutTelemetry.xhtml
+++ b/toolkit/content/aboutTelemetry.xhtml
@@ -133,16 +133,21 @@
<div class="header">
<div id="sectionTitle" class="header-name">
&aboutTelemetry.pageTitle;
</div>
<input type="text" id="search" placeholder=""/>
<select id="processes" hidden="true"></select>
</div>
+ <div id="no-search-results" hidden="true">
+ <span id="no-search-results-text"></span>
+ <div class="no-search-results-image"></div>
+ </div>
+
<section id="home-section" class="active">
<h3 id="page-subtitle"></h3>
<p id="home-explanation"></p>
<p id="ping-explanation"></p>
</section>
<section id="raw-payload-section">
<button id="payload-json-viewer">&aboutTelemetry.showInFirefoxJsonViewer;</button>
--- a/toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
+++ b/toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
@@ -41,16 +41,21 @@ 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ā
+# Note to translators:
+# - %1$S will be replaced by the section name from the structure of the ping. More info about it can be found here : http://gecko.readthedocs.io/en/latest/toolkit/components/telemetry/telemetry/data/main-ping.html
+# - %2$S will be replaced by the current text in the search input
+noSearchResults = Sorry! There are no results in %1$S for ā%2$Sā
+
telemetryPingTypeAll = all
telemetryLogTitle = Telemetry Log
telemetryLogHeadingId = Id
telemetryLogHeadingTimestamp = Timestamp