mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 23:35:34 +00:00
Bug 1716748 - Add a nightly only viewer for interaction metadata. r=mak
Differential Revision: https://phabricator.services.mozilla.com/D117999
This commit is contained in:
parent
9d1ed273fe
commit
9b29670324
@ -76,6 +76,13 @@ if (AppConstants.NIGHTLY_BUILD) {
|
||||
gExceptionPaths.push("resource://builtin-addons/translations/");
|
||||
}
|
||||
|
||||
if (AppConstants.NIGHTLY_BUILD) {
|
||||
// This is nightly-only debug tool.
|
||||
gExceptionPaths.push(
|
||||
"chrome://browser/content/places/interactionsViewer.html"
|
||||
);
|
||||
}
|
||||
|
||||
// Each whitelist entry should have a comment indicating which file is
|
||||
// referencing the whitelisted file in a way that the test can't detect, or a
|
||||
// bug number to remove or use the file if it is indeed currently unreferenced.
|
||||
|
@ -21,3 +21,8 @@ browser.jar:
|
||||
* content/browser/places/bookmarksSidebar.xhtml (content/bookmarksSidebar.xhtml)
|
||||
content/browser/places/bookmarksSidebar.js (content/bookmarksSidebar.js)
|
||||
content/browser/places/editBookmark.js (content/editBookmark.js)
|
||||
#ifdef NIGHTLY_BUILD
|
||||
content/browser/places/interactionsViewer.css (metadataViewer/interactionsViewer.css)
|
||||
content/browser/places/interactionsViewer.html (metadataViewer/interactionsViewer.html)
|
||||
content/browser/places/interactionsViewer.js (metadataViewer/interactionsViewer.js)
|
||||
#endif
|
||||
|
@ -0,0 +1,47 @@
|
||||
/* 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/. */
|
||||
|
||||
body {
|
||||
padding: .5em 2em;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.message-bar-icon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#metadataLimit {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
#metadataViewer {
|
||||
display: grid;
|
||||
grid-template-columns: max-content fit-content(100%) repeat(4, max-content);
|
||||
}
|
||||
|
||||
#metadataViewer > div {
|
||||
padding: .3em 1em;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Sets the first row of elements to bold. The number is the number of columns */
|
||||
#metadataViewer > div:nth-child(-n+6) {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Highlights every other row to make visual scanning of the table easier.
|
||||
The numbers need to be adapted if the number of columns changes. */
|
||||
#metadataViewer > div:nth-child(6n+7):nth-child(12n+7),
|
||||
#metadataViewer > div:nth-child(6n+8):nth-child(12n+8),
|
||||
#metadataViewer > div:nth-child(6n+9):nth-child(12n+9),
|
||||
#metadataViewer > div:nth-child(6n+10):nth-child(12n+10),
|
||||
#metadataViewer > div:nth-child(6n+11):nth-child(12n+11),
|
||||
#metadataViewer > div:nth-child(6n+12):nth-child(12n+12) {
|
||||
background: var(--in-content-box-background-odd);
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
<!--
|
||||
# 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/.
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Interactions Debug Viewer</title>
|
||||
<script type="module" src="chrome://browser/content/places/interactionsViewer.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://global/skin/in-content/common.css">
|
||||
<link rel="stylesheet" type="text/css" href="chrome://browser/content/places/interactionsViewer.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="enabledWarning" class="message-bar message-bar-warning" hidden>
|
||||
<img class="message-bar-icon" src="chrome://browser/skin/warning.svg">
|
||||
<descripton class="message-bar-description">
|
||||
You need to have <code>browser.places.interactions.enabled</code>
|
||||
set to true (and restart) for metadata recording to be enabled.
|
||||
</descripton>
|
||||
</div>
|
||||
<h1>Page Metadata</h1>
|
||||
<div id="metadataLimit"></div>
|
||||
<div id="metadataViewer">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
146
browser/components/places/metadataViewer/interactionsViewer.js
Normal file
146
browser/components/places/metadataViewer/interactionsViewer.js
Normal file
@ -0,0 +1,146 @@
|
||||
/* 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/. */
|
||||
|
||||
/* eslint-env module */
|
||||
|
||||
const { Interactions } = ChromeUtils.import(
|
||||
"resource:///modules/Interactions.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { PlacesUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/PlacesUtils.jsm"
|
||||
);
|
||||
|
||||
const metadataHandler = new (class {
|
||||
/**
|
||||
* Maximum number of rows to display by default.
|
||||
*
|
||||
* @typedef {number}
|
||||
*/
|
||||
#maxRows = 100;
|
||||
|
||||
/**
|
||||
* A reference to the database connection.
|
||||
*
|
||||
* @typedef {mozIStorageConnection}
|
||||
*/
|
||||
#db = null;
|
||||
|
||||
/**
|
||||
* A map of columns that are displayed by default.
|
||||
* @note If you change the number of columns, then you also need to change
|
||||
* the css to account for the new number.
|
||||
*
|
||||
* - The key is the column name in the database.
|
||||
* - The header is the column header on the table.
|
||||
* - The modifier is a function to modify the returned value from the database
|
||||
* for display.
|
||||
* - includeTitle determines if the title attribute should be set on that
|
||||
* column, for tooltips, e.g. if an element is likely to overflow.
|
||||
*
|
||||
* @typedef {Map<string, object>}
|
||||
*/
|
||||
#columnMap = new Map([
|
||||
["id", { header: "ID" }],
|
||||
["url", { header: "URL", includeTitle: true }],
|
||||
[
|
||||
"updated_at",
|
||||
{
|
||||
header: "Updated",
|
||||
modifier: updatedAt => new Date(updatedAt).toLocaleString(),
|
||||
},
|
||||
],
|
||||
[
|
||||
"total_view_time",
|
||||
{
|
||||
header: "View Time (s)",
|
||||
modifier: totalViewTime => (totalViewTime / 1000).toFixed(2),
|
||||
},
|
||||
],
|
||||
[
|
||||
"typing_time",
|
||||
{
|
||||
header: "Typing Time (s)",
|
||||
modifier: typingTime => (typingTime / 1000).toFixed(2),
|
||||
},
|
||||
],
|
||||
["key_presses", { header: "Key Presses" }],
|
||||
]);
|
||||
|
||||
async start() {
|
||||
this.#setupUI();
|
||||
this.#db = await PlacesUtils.promiseDBConnection();
|
||||
await this.#updateDisplay();
|
||||
setInterval(this.#updateDisplay.bind(this), 10000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the initial table layout to the correct size.
|
||||
*/
|
||||
#setupUI() {
|
||||
let tableBody = document.createDocumentFragment();
|
||||
let header = document.createDocumentFragment();
|
||||
for (let details of this.#columnMap.values()) {
|
||||
let columnDiv = document.createElement("div");
|
||||
columnDiv.textContent = details.header;
|
||||
header.appendChild(columnDiv);
|
||||
}
|
||||
tableBody.appendChild(header);
|
||||
|
||||
for (let i = 0; i < this.#maxRows; i++) {
|
||||
let row = document.createDocumentFragment();
|
||||
for (let j = 0; j < this.#columnMap.size; j++) {
|
||||
row.appendChild(document.createElement("div"));
|
||||
}
|
||||
tableBody.appendChild(row);
|
||||
}
|
||||
let viewer = document.getElementById("metadataViewer");
|
||||
viewer.appendChild(tableBody);
|
||||
|
||||
let limit = document.getElementById("metadataLimit");
|
||||
limit.textContent = `Maximum rows displayed: ${this.#maxRows}.`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the current metadata from the database and updates the display.
|
||||
*/
|
||||
async #updateDisplay() {
|
||||
let rows = await this.#db.executeCached(
|
||||
`SELECT m.id AS id, h.url AS url, updated_at, total_view_time,
|
||||
typing_time, key_presses FROM moz_places_metadata m
|
||||
JOIN moz_places h ON h.id = m.place_id
|
||||
ORDER BY updated_at DESC
|
||||
LIMIT ${this.#maxRows}`
|
||||
);
|
||||
let viewer = document.getElementById("metadataViewer");
|
||||
let index = this.#columnMap.size;
|
||||
for (let row of rows) {
|
||||
for (let [column, details] of this.#columnMap.entries()) {
|
||||
let value = row.getResultByName(column);
|
||||
|
||||
if (details.includeTitle) {
|
||||
viewer.children[index].setAttribute("title", value);
|
||||
}
|
||||
|
||||
viewer.children[index].textContent = details.modifier
|
||||
? details.modifier(value)
|
||||
: value;
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
function checkPrefs() {
|
||||
if (
|
||||
!Services.prefs.getBoolPref("browser.places.interactions.enabled", false)
|
||||
) {
|
||||
let warning = document.getElementById("enabledWarning");
|
||||
warning.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
checkPrefs();
|
||||
metadataHandler.start().catch(console.error);
|
Loading…
Reference in New Issue
Block a user