зеркало из https://github.com/mozilla/gecko-dev.git
about:crashes: updated user interface (bug 1476062); r=mconley,flod
The about:crashes page's user interface is being updated (bug 1463515). - changed crash submission to be done through button press instead of link clicking - this allows users to know that they are submitting the crash - updated visuals to match new mock-up - mock-up image: https://bug1463515.bmoattachments.org/attachment.cgi?id=8990380 - added new Fluent strings that are needed for the new user interface - modernized the surrounding code Differential Revision: https://phabricator.services.mozilla.com/D2792 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
157b6e767a
Коммит
dc84fa05b8
|
@ -8,59 +8,68 @@
|
|||
min-width: 30em;
|
||||
max-width: 60em;
|
||||
}
|
||||
|
||||
table {
|
||||
clear: both;
|
||||
width: 90%;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
th {
|
||||
font-size: 130%;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
th:-moz-locale-dir(rtl) {
|
||||
text-align: right;
|
||||
}
|
||||
/* name */
|
||||
th:first-child {
|
||||
padding-inline-end: 2em;
|
||||
}
|
||||
/* submitted */
|
||||
th:last-child {
|
||||
text-align: center;
|
||||
}
|
||||
:link, :visited {
|
||||
display: block;
|
||||
min-height: 17px;
|
||||
}
|
||||
/* date */
|
||||
td:first-child + td {
|
||||
width: 0;
|
||||
padding-inline-start: 1em;
|
||||
padding-inline-end: .5em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
/* time */
|
||||
td:last-child {
|
||||
width: 0;
|
||||
padding-inline-start: .5em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#clear-reports {
|
||||
.float-right {
|
||||
float: right;
|
||||
}
|
||||
#clear-reports:-moz-locale-dir(rtl) {
|
||||
float: left;
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
.table-title-container {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.wide-button {
|
||||
display: block;
|
||||
min-height: 32px;
|
||||
padding-left: 30px;
|
||||
padding-right: 30px;
|
||||
}
|
||||
|
||||
.submitting {
|
||||
background-image: url(chrome://global/skin/icons/loading.png);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right;
|
||||
background-size: 16px;
|
||||
}
|
||||
.submitting .submit-crash-button-label {
|
||||
display: none;
|
||||
}
|
||||
.failed-to-submit {
|
||||
color: #ca8695;
|
||||
}
|
||||
|
||||
a.button-as-link {
|
||||
-moz-appearance: none;
|
||||
min-height: 30px;
|
||||
color: var(--in-content-text-color) !important;
|
||||
border: 1px solid var(--in-content-box-border-color) !important;
|
||||
border-radius: 2px;
|
||||
background-color: var(--in-content-page-background);
|
||||
line-height: 30px;
|
||||
margin: 4px 8px;
|
||||
/* Ensure font-size isn't overridden by widget styling (e.g. in forms.css) */
|
||||
font-size: 1em;
|
||||
}
|
||||
a.button-as-link:hover {
|
||||
background-color: var(--in-content-box-background-hover) !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
h2.lighter-font-weight {
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
html[dir=ltr] th {
|
||||
text-align: left;
|
||||
}
|
||||
html[dir=rtl] th {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
.submitting {
|
||||
|
|
|
@ -2,148 +2,211 @@
|
|||
* 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/. */
|
||||
|
||||
var reportURL;
|
||||
let reportURL;
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/CrashReports.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "CrashSubmit",
|
||||
"resource://gre/modules/CrashSubmit.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "CrashSubmit", "resource://gre/modules/CrashSubmit.jsm");
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
populateReportList();
|
||||
document.getElementById("clear-reports").addEventListener("click", function() {
|
||||
clearReports().then(null, Cu.reportError);
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
populateReportLists();
|
||||
document.getElementById("clearUnsubmittedReports").addEventListener("click", () => {
|
||||
clearUnsubmittedReports().catch(Cu.reportError);
|
||||
});
|
||||
document.getElementById("clearSubmittedReports").addEventListener("click", () => {
|
||||
clearSubmittedReports().catch(Cu.reportError);
|
||||
});
|
||||
});
|
||||
|
||||
const buildID = Services.appinfo.appBuildID;
|
||||
|
||||
function submitPendingReport(event) {
|
||||
let link = event.target;
|
||||
let id = link.firstChild.textContent;
|
||||
link.className = "submitting";
|
||||
CrashSubmit.submit(id, { noThrottle: true }).then(
|
||||
(remoteCrashID) => {
|
||||
link.className = "";
|
||||
// Reset the link to point at our new crash report. This way, if the
|
||||
// user clicks "Back", the link will be correct.
|
||||
link.firstChild.textContent = remoteCrashID;
|
||||
link.setAttribute("id", remoteCrashID);
|
||||
link.removeEventListener("click", submitPendingReport, true);
|
||||
|
||||
if (reportURL) {
|
||||
link.setAttribute("href", reportURL + remoteCrashID);
|
||||
// redirect the user to their brand new crash report
|
||||
window.location.href = reportURL + remoteCrashID;
|
||||
}
|
||||
},
|
||||
() => {
|
||||
// XXX: do something more useful here
|
||||
link.className = "";
|
||||
|
||||
// Dispatch an event, useful for testing
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("CrashSubmitFailed", true, false);
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
function populateReportList() {
|
||||
/**
|
||||
* Adds the crash reports with submission buttons and links
|
||||
* to the unsubmitted and submitted crash report lists.
|
||||
* If breakpad.reportURL is not set, displays a misconfiguration message
|
||||
* instead.
|
||||
*/
|
||||
function populateReportLists() {
|
||||
try {
|
||||
reportURL = Services.prefs.getCharPref("breakpad.reportURL");
|
||||
// Ignore any non http/https urls
|
||||
if (!/^https?:/i.test(reportURL))
|
||||
if (!/^https?:/i.test(reportURL)) {
|
||||
reportURL = null;
|
||||
} catch (e) { }
|
||||
if (!reportURL) {
|
||||
document.getElementById("clear-reports").style.display = "none";
|
||||
document.getElementById("reportList").style.display = "none";
|
||||
document.getElementById("noConfig").style.display = "block";
|
||||
return;
|
||||
}
|
||||
let reports = CrashReports.getReports();
|
||||
|
||||
if (reports.length == 0) {
|
||||
document.getElementById("clear-reports").style.display = "none";
|
||||
document.getElementById("reportList").style.display = "none";
|
||||
document.getElementById("noReports").style.display = "block";
|
||||
return;
|
||||
}
|
||||
|
||||
var dateFormatter;
|
||||
var timeFormatter;
|
||||
try {
|
||||
dateFormatter = new Services.intl.DateTimeFormat(undefined, { dateStyle: "short" });
|
||||
timeFormatter = new Services.intl.DateTimeFormat(undefined, { timeStyle: "short" });
|
||||
} catch (e) {
|
||||
// XXX Fallback to be removed once bug 1215247 is complete
|
||||
// and the Intl API is available on all platforms.
|
||||
dateFormatter = {
|
||||
format(date) {
|
||||
return date.toLocaleDateString();
|
||||
reportURL = null;
|
||||
}
|
||||
};
|
||||
timeFormatter = {
|
||||
format(date) {
|
||||
return date.toLocaleTimeString();
|
||||
if (!reportURL) {
|
||||
document.getElementById("noConfig").classList.remove("hidden");
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
var reportURI = Services.io.newURI(reportURL);
|
||||
// resolving this URI relative to /report/index
|
||||
var aboutThrottling = Services.io.newURI("../../about/throttling", null, reportURI);
|
||||
const reports = CrashReports.getReports();
|
||||
const dateFormatter = new Services.intl.DateTimeFormat(undefined, {
|
||||
timeStyle: "short",
|
||||
dateStyle: "short"
|
||||
});
|
||||
reports.forEach(report => addReportRow(report.pending, report.id, report.date, dateFormatter));
|
||||
showAppropriateSections();
|
||||
}
|
||||
|
||||
for (var i = 0; i < reports.length; i++) {
|
||||
var row = document.createElement("tr");
|
||||
var cell = document.createElement("td");
|
||||
row.appendChild(cell);
|
||||
var link = document.createElement("a");
|
||||
if (reports[i].pending) {
|
||||
link.setAttribute("href", aboutThrottling.spec);
|
||||
link.addEventListener("click", submitPendingReport, true);
|
||||
} else {
|
||||
link.setAttribute("href", reportURL + reports[i].id);
|
||||
}
|
||||
link.setAttribute("id", reports[i].id);
|
||||
link.classList.add("crashReport");
|
||||
link.appendChild(document.createTextNode(reports[i].id));
|
||||
cell.appendChild(link);
|
||||
/**
|
||||
* Adds a crash report with the appropriate submission button
|
||||
* or viewing link to the unsubmitted or submitted report list
|
||||
* based on isPending.
|
||||
*
|
||||
* @param {Boolean} isPending whether the crash is up for submission
|
||||
* @param {String} id the unique id of the crash report
|
||||
* @param {Date} date either the date of crash or date of submission
|
||||
* @param {Object} dateFormatter formatter for presenting dates to users
|
||||
*/
|
||||
function addReportRow(isPending, id, date, dateFormatter) {
|
||||
const rowTemplate = document.getElementById("crashReportRow");
|
||||
const row = document.importNode(rowTemplate.content, true).querySelector("tr");
|
||||
row.id = id;
|
||||
|
||||
var date = new Date(reports[i].date);
|
||||
cell = document.createElement("td");
|
||||
cell.appendChild(document.createTextNode(dateFormatter.format(date)));
|
||||
row.appendChild(cell);
|
||||
cell = document.createElement("td");
|
||||
cell.appendChild(document.createTextNode(timeFormatter.format(date)));
|
||||
row.appendChild(cell);
|
||||
if (reports[i].pending) {
|
||||
const cells = row.querySelectorAll("td");
|
||||
cells[0].appendChild(document.createTextNode(id));
|
||||
cells[1].appendChild(document.createTextNode(dateFormatter.format(date)));
|
||||
|
||||
if (isPending) {
|
||||
const buttonTemplate = document.getElementById("crashSubmitButton");
|
||||
const button = document.importNode(buttonTemplate.content, true).querySelector("button");
|
||||
const buttonText = button.querySelector("span");
|
||||
button.addEventListener("click",
|
||||
() => submitPendingReport(id, row, button, buttonText, dateFormatter));
|
||||
cells[2].appendChild(button);
|
||||
document.getElementById("unsubmitted").appendChild(row);
|
||||
} else {
|
||||
const linkTemplate = document.getElementById("viewCrashLink");
|
||||
const link = document.importNode(linkTemplate.content, true).querySelector("a");
|
||||
link.href = `${reportURL}${id}`;
|
||||
cells[2].appendChild(link);
|
||||
document.getElementById("submitted").appendChild(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var clearReports = async function() {
|
||||
/**
|
||||
* Shows or hides each of the unsubmitted and submitted report list
|
||||
* based on whether they contain at least one crash report.
|
||||
* If hidden, the submitted report list is replaced by a message
|
||||
* indicating that no crash reports have been submitted.
|
||||
*/
|
||||
function showAppropriateSections() {
|
||||
let hasUnsubmitted = document.getElementById("unsubmitted").childElementCount > 0;
|
||||
document.getElementById("reportListUnsubmitted").classList.toggle("hidden", !hasUnsubmitted);
|
||||
|
||||
let hasSubmitted = document.getElementById("submitted").childElementCount > 0;
|
||||
document.getElementById("reportListSubmitted").classList.toggle("hidden", !hasSubmitted);
|
||||
document.getElementById("noSubmittedReports").classList.toggle("hidden", hasSubmitted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the provided button to display a spinner. Then, tries to submit the
|
||||
* crash report for the provided id. On success, removes the crash report from
|
||||
* the list of unsubmitted crash reports and adds a new crash report to the list
|
||||
* of submitted crash reports. On failure, changes the provided button to display
|
||||
* a red error message.
|
||||
*
|
||||
* @param {String} reportId the unique id of the crash report
|
||||
* @param {HTMLTableRowElement} row the table row of the crash report
|
||||
* @param {HTMLButtonElement} button the button pressed to start the submission
|
||||
* @param {HTMLSpanElement} buttonText the text inside the pressed button
|
||||
* @param {Object} dateFormatter formatter for presenting dates to users
|
||||
*/
|
||||
function submitPendingReport(reportId, row, button, buttonText, dateFormatter) {
|
||||
button.classList.add("submitting");
|
||||
CrashSubmit.submit(reportId, { noThrottle: true }).then(remoteCrashID => {
|
||||
document.getElementById("unsubmitted").removeChild(row);
|
||||
const report = CrashReports.getReports().filter(report => report.id === remoteCrashID);
|
||||
addReportRow(false, remoteCrashID, report.date, dateFormatter);
|
||||
showAppropriateSections();
|
||||
dispatchEvent("CrashSubmitSucceeded");
|
||||
},
|
||||
() => {
|
||||
button.classList.remove("submitting");
|
||||
button.classList.add("failed-to-submit");
|
||||
document.l10n.setAttributes(buttonText, "submit-crash-button-failure-label");
|
||||
dispatchEvent("CrashSubmitFailed");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes unsubmitted and old crash reports from the user's device.
|
||||
* Then, hides the list of unsubmitted crash reports.
|
||||
*/
|
||||
async function clearUnsubmittedReports() {
|
||||
const [title, description] = await document.l10n.formatValues([
|
||||
{id: "delete-confirm-title"},
|
||||
{id: "delete-confirm-description"},
|
||||
{id: "delete-unsubmitted-description"},
|
||||
]);
|
||||
if (!Services.prompt.confirm(window, title, description)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cleanupFolder = async function(path, filter) {
|
||||
let iterator = new OS.File.DirectoryIterator(path);
|
||||
await cleanupFolder(CrashReports.pendingDir.path);
|
||||
await clearOldReports();
|
||||
document.getElementById("reportListUnsubmitted").classList.add("hidden");
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes submitted and old crash reports from the user's device.
|
||||
* Then, hides the list of submitted crash reports.
|
||||
*/
|
||||
async function clearSubmittedReports() {
|
||||
const [title, description] = await document.l10n.formatValues([
|
||||
{id: "delete-confirm-title"},
|
||||
{id: "delete-submitted-description"},
|
||||
]);
|
||||
if (!Services.prompt.confirm(window, title, description)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await cleanupFolder(
|
||||
CrashReports.submittedDir.path,
|
||||
async entry => entry.name.startsWith("bp-") && entry.name.endsWith(".txt"),
|
||||
);
|
||||
await clearOldReports();
|
||||
document.getElementById("reportListSubmitted").classList.add("hidden");
|
||||
document.getElementById("noSubmittedReports").classList.remove("hidden");
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes old crash reports from the user's device.
|
||||
*/
|
||||
async function clearOldReports() {
|
||||
const oneYearAgo = Date.now() - 31586000000;
|
||||
await cleanupFolder(CrashReports.reportsDir.path, async entry => {
|
||||
if (!entry.name.startsWith("InstallTime") || entry.name == "InstallTime" + buildID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let date = entry.winLastWriteDate;
|
||||
if (!date) {
|
||||
const stat = await OS.File.stat(entry.path);
|
||||
date = stat.lastModificationDate;
|
||||
}
|
||||
return date < oneYearAgo;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes files from the user's device at the specified path
|
||||
* that match the provided filter.
|
||||
*
|
||||
* @param {String} path the directory location to delete form
|
||||
* @param {Function} filter function taking in a file entry and
|
||||
* returning whether to delete the file
|
||||
*/
|
||||
async function cleanupFolder(path, filter) {
|
||||
const iterator = new OS.File.DirectoryIterator(path);
|
||||
try {
|
||||
await iterator.forEach(async function(aEntry) {
|
||||
if (!filter || (await filter(aEntry))) {
|
||||
await OS.File.remove(aEntry.path);
|
||||
await iterator.forEach(async entry => {
|
||||
if (!filter || (await filter(entry))) {
|
||||
await OS.File.remove(entry.path);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
|
@ -153,31 +216,15 @@ var clearReports = async function() {
|
|||
} finally {
|
||||
iterator.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
await cleanupFolder(CrashReports.submittedDir.path, function(aEntry) {
|
||||
return aEntry.name.startsWith("bp-") && aEntry.name.endsWith(".txt");
|
||||
});
|
||||
|
||||
let oneYearAgo = Date.now() - 31586000000;
|
||||
await cleanupFolder(CrashReports.reportsDir.path, async function(aEntry) {
|
||||
if (!aEntry.name.startsWith("InstallTime") ||
|
||||
aEntry.name == "InstallTime" + buildID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let date = aEntry.winLastWriteDate;
|
||||
if (!date) {
|
||||
let stat = await OS.File.stat(aEntry.path);
|
||||
date = stat.lastModificationDate;
|
||||
}
|
||||
|
||||
return (date < oneYearAgo);
|
||||
});
|
||||
|
||||
await cleanupFolder(CrashReports.pendingDir.path);
|
||||
|
||||
document.getElementById("clear-reports").style.display = "none";
|
||||
document.getElementById("reportList").style.display = "none";
|
||||
document.getElementById("noReports").style.display = "block";
|
||||
};
|
||||
/**
|
||||
* Dispatches an event with the specified name.
|
||||
*
|
||||
* @param {String} name the name of the event
|
||||
*/
|
||||
function dispatchEvent(name) {
|
||||
const event = document.createEvent("Events");
|
||||
event.initEvent(name, true, false);
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
|
|
@ -4,48 +4,69 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<link rel="localization" href="crashreporter/aboutcrashes.ftl"/>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://global/content/crashes.css"/>
|
||||
<link rel="stylesheet" media="screen, projection" type="text/css"
|
||||
<head>
|
||||
<link rel="localization" href="crashreporter/aboutcrashes.ftl"/>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://global/content/crashes.css"/>
|
||||
<link rel="stylesheet" media="screen, projection" type="text/css"
|
||||
href="chrome://global/skin/in-content/common.css"/>
|
||||
<script type="application/javascript" src="chrome://global/content/crashes.js"/>
|
||||
<script type="text/javascript" src="chrome://global/content/l10n.js"/>
|
||||
<script type="application/javascript" src="chrome://global/content/crashes.js"/>
|
||||
<script type="text/javascript" src="chrome://global/content/l10n.js"/>
|
||||
<title data-l10n-id="crash-reports-title"></title>
|
||||
</head>
|
||||
|
||||
<title data-l10n-id="crash-reports-title"></title>
|
||||
</head><body>
|
||||
<button id="clear-reports" data-l10n-id="clear-all-reports-label"></button>
|
||||
<div id="reportList">
|
||||
<div id="reportListUnsubmitted">
|
||||
<h1 data-l10n-id="crashes-unsubmitted-label"></h1>
|
||||
<body>
|
||||
<p id="noConfig" class="hidden" data-l10n-id="no-config-label"></p>
|
||||
<p id="noSubmittedReports" class="hidden" data-l10n-id="no-reports-label"></p>
|
||||
|
||||
<div id="reportListSubmitted" class="hidden">
|
||||
<div class="table-title-container">
|
||||
<h2 class="lighter-font-weight" data-l10n-id="crashes-submitted-label"></h2>
|
||||
<button id="clearSubmittedReports" class="wide-button" data-l10n-id="delete-button-label"></button>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-l10n-id="id-heading"></th>
|
||||
<th colspan="2" data-l10n-id="date-crashed-heading"></th>
|
||||
<th data-l10n-id="date-submitted-heading"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="unsubmitted">
|
||||
</tbody>
|
||||
<tbody id="submitted"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="reportListSubmitted">
|
||||
<h1 data-l10n-id="crashes-submitted-label"></h1>
|
||||
|
||||
<div id="reportListUnsubmitted" class="hidden">
|
||||
<div class="table-title-container">
|
||||
<h2 class="lighter-font-weight" data-l10n-id="crashes-unsubmitted-label"></h2>
|
||||
<button id="clearUnsubmittedReports" class="wide-button" data-l10n-id="delete-button-label"></button>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-l10n-id="id-heading"></th>
|
||||
<th colspan="2" data-l10n-id="date-submitted-heading"></th>
|
||||
<th data-l10n-id="date-crashed-heading"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="submitted">
|
||||
</tbody>
|
||||
<tbody id="unsubmitted"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<p id="noReports" style="display: none" data-l10n-id="no-reports-label"></p>
|
||||
<p id="noConfig" style="display: none" data-l10n-id="no-config-label"></p>
|
||||
</body>
|
||||
</body>
|
||||
|
||||
<template id="crashReportRow">
|
||||
<tr>
|
||||
<td class="crash-id"></td>
|
||||
<td></td>
|
||||
<td class="float-right"></td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<template id="crashSubmitButton">
|
||||
<button class="submit-button wide-button">
|
||||
<span class="submit-crash-button-label" data-l10n-id="submit-crash-button-label"></span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<template id="viewCrashLink">
|
||||
<a class="crash-link button-as-link wide-button" data-l10n-id="view-crash-button-label"></a>
|
||||
</template>
|
||||
</html>
|
||||
|
|
|
@ -1,22 +1,28 @@
|
|||
add_task(async function test() {
|
||||
let appD = make_fake_appdir();
|
||||
let crD = appD.clone();
|
||||
const appD = make_fake_appdir();
|
||||
const crD = appD.clone();
|
||||
crD.append("Crash Reports");
|
||||
let crashes = add_fake_crashes(crD, 5);
|
||||
const crashes = add_fake_crashes(crD, 5);
|
||||
// sanity check
|
||||
let appDtest = Services.dirsvc.get("UAppData", Ci.nsIFile);
|
||||
const appDtest = Services.dirsvc.get("UAppData", Ci.nsIFile);
|
||||
ok(appD.equals(appDtest), "directory service provider registered ok");
|
||||
|
||||
await BrowserTestUtils.withNewTab({ gBrowser, url: "about:crashes" }, function(browser) {
|
||||
await BrowserTestUtils.withNewTab({ gBrowser, url: "about:crashes" }, browser => {
|
||||
info("about:crashes loaded");
|
||||
return ContentTask.spawn(browser, crashes, function(crashes) {
|
||||
let doc = content.document;
|
||||
let crashlinks = doc.getElementById("submitted").querySelectorAll(".crashReport");
|
||||
Assert.equal(crashlinks.length, crashes.length,
|
||||
"about:crashes lists correct number of crash reports");
|
||||
return ContentTask.spawn(browser, crashes, crashes => {
|
||||
const doc = content.document;
|
||||
const crashIds = doc.getElementsByClassName("crash-id");
|
||||
Assert.equal(
|
||||
crashIds.length,
|
||||
crashes.length,
|
||||
"about:crashes lists correct number of crash reports",
|
||||
);
|
||||
for (let i = 0; i < crashes.length; i++) {
|
||||
Assert.equal(crashlinks[i].firstChild.textContent, crashes[i].id,
|
||||
i + ": crash ID is correct");
|
||||
Assert.equal(
|
||||
crashIds[i].textContent,
|
||||
crashes[i].id,
|
||||
i + ": crash ID is correct",
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,21 +16,20 @@ function cleanup_and_finish() {
|
|||
* NB: This function is run in the child process via ContentTask.spawn.
|
||||
*/
|
||||
function check_crash_list(crashes) {
|
||||
let doc = content.document;
|
||||
let crashlinks = doc.getElementsByClassName("crashReport");
|
||||
Assert.equal(crashlinks.length, crashes.length,
|
||||
"about:crashes lists correct number of crash reports");
|
||||
// no point in checking this if the lists aren't the same length
|
||||
if (crashlinks.length == crashes.length) {
|
||||
const doc = content.document;
|
||||
const crashIds = doc.getElementsByClassName("crash-id");
|
||||
|
||||
Assert.equal(
|
||||
crashIds.length,
|
||||
crashes.length,
|
||||
"about:crashes lists correct number of crash reports",
|
||||
);
|
||||
for (let i = 0; i < crashes.length; i++) {
|
||||
Assert.equal(crashlinks[i].id, crashes[i].id, i + ": crash ID is correct");
|
||||
if (crashes[i].pending) {
|
||||
// we set the breakpad.reportURL pref in test()
|
||||
Assert.equal(crashlinks[i].getAttribute("href"),
|
||||
"http://example.com/browser/toolkit/crashreporter/about/throttling",
|
||||
"pending URL links to the correct static page");
|
||||
}
|
||||
}
|
||||
Assert.equal(
|
||||
crashIds[i].textContent,
|
||||
crashes[i].id,
|
||||
i + ": crash ID is correct",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,10 +42,16 @@ function check_crash_list(crashes) {
|
|||
* Additionally, click "back" and verify that the link now points to our new
|
||||
*/
|
||||
function check_submit_pending(tab, crashes) {
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
const browser = gBrowser.getBrowserForTab(tab);
|
||||
let SubmittedCrash = null;
|
||||
let CrashID = null;
|
||||
let CrashURL = null;
|
||||
function csp_onsuccess() {
|
||||
const crashLinks = content.document.getElementsByClassName("crash-link");
|
||||
// Get the last link since it is appended to the end of the list
|
||||
const link = crashLinks[crashLinks.length - 1];
|
||||
link.click();
|
||||
}
|
||||
function csp_onload() {
|
||||
// loaded the crash report page
|
||||
ok(true, "got submission onload");
|
||||
|
@ -99,47 +104,50 @@ function check_submit_pending(tab, crashes) {
|
|||
ok(false, "failed to submit crash report!");
|
||||
cleanup_and_finish();
|
||||
}
|
||||
browser.addEventListener("CrashSubmitSucceeded", csp_onsuccess, true);
|
||||
browser.addEventListener("CrashSubmitFailed", csp_fail, true);
|
||||
BrowserTestUtils.browserLoaded(browser, false, (url) => url !== "about:crashes").then(csp_onload);
|
||||
function csp_pageshow() {
|
||||
ContentTask.spawn(browser, { CrashID, CrashURL }, function({ CrashID, CrashURL }) {
|
||||
Assert.equal(content.location.href, "about:crashes", "navigated back successfully");
|
||||
let link = content.document.getElementById(CrashID);
|
||||
const link = content.document.getElementById(CrashID).getElementsByClassName("crash-link")[0];
|
||||
Assert.notEqual(link, null, "crash report link changed correctly");
|
||||
if (link)
|
||||
if (link) {
|
||||
Assert.equal(link.href, CrashURL, "crash report link points to correct href");
|
||||
}
|
||||
}).then(cleanup_and_finish);
|
||||
}
|
||||
|
||||
// try submitting the pending report
|
||||
for (let crash of crashes) {
|
||||
for (const crash of crashes) {
|
||||
if (crash.pending) {
|
||||
SubmittedCrash = crash;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ContentTask.spawn(browser, SubmittedCrash.id, function(id) {
|
||||
let link = content.document.getElementById(id);
|
||||
link.click();
|
||||
ContentTask.spawn(browser, SubmittedCrash.id, id => {
|
||||
const submitButton = content.document.getElementById(id).getElementsByClassName("submit-button")[0];
|
||||
submitButton.click();
|
||||
});
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
let appD = make_fake_appdir();
|
||||
let crD = appD.clone();
|
||||
const appD = make_fake_appdir();
|
||||
const crD = appD.clone();
|
||||
crD.append("Crash Reports");
|
||||
let crashes = add_fake_crashes(crD, 1);
|
||||
const crashes = add_fake_crashes(crD, 1);
|
||||
// we don't need much data here, it's not going to a real Socorro
|
||||
crashes.push(addPendingCrashreport(crD,
|
||||
crashes.push(addPendingCrashreport(
|
||||
crD,
|
||||
crashes[crashes.length - 1].date + 60000,
|
||||
{"ServerURL": "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs",
|
||||
{
|
||||
"ServerURL": "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs",
|
||||
"ProductName": "Test App",
|
||||
// test that we don't truncate
|
||||
// at = (bug 512853)
|
||||
"Foo": "ABC=XYZ"
|
||||
}));
|
||||
"Foo": "ABC=XYZ", // test that we don't truncat eat = (bug 512853)
|
||||
}
|
||||
));
|
||||
crashes.sort((a, b) => b.date - a.date);
|
||||
|
||||
// set this pref so we can link to our test server
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
function check_clear_visible(browser, aVisible) {
|
||||
return ContentTask.spawn(browser, aVisible, function(aVisible) {
|
||||
let doc = content.document;
|
||||
const doc = content.document;
|
||||
let visible = false;
|
||||
let button = doc.getElementById("clear-reports");
|
||||
if (button) {
|
||||
let style = doc.defaultView.getComputedStyle(button);
|
||||
if (style.display != "none" &&
|
||||
style.visibility == "visible")
|
||||
const reportListSubmitted = doc.getElementById("reportListSubmitted");
|
||||
if (reportListSubmitted) {
|
||||
const style = doc.defaultView.getComputedStyle(reportListSubmitted);
|
||||
if (style.display !== "none" && style.visibility === "visible") {
|
||||
visible = true;
|
||||
}
|
||||
}
|
||||
Assert.equal(visible, aVisible,
|
||||
"clear reports button is " + (aVisible ? "visible" : "hidden"));
|
||||
"clear submitted reports button is " + (aVisible ? "visible" : "hidden"));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -2,41 +2,23 @@
|
|||
* 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/. */
|
||||
|
||||
function clickClearReports(browser) {
|
||||
let doc = content.document;
|
||||
|
||||
let button = doc.getElementById("clear-reports");
|
||||
|
||||
if (!button) {
|
||||
Assert.ok(false, "Button not found");
|
||||
return Promise.resolve();
|
||||
function clickClearReports() {
|
||||
const doc = content.document;
|
||||
const reportListUnsubmitted = doc.getElementById("reportListUnsubmitted");
|
||||
const reportListSubmitted = doc.getElementById("reportListSubmitted");
|
||||
if (!reportListUnsubmitted || !reportListSubmitted) {
|
||||
Assert.ok(false, "Report list not found");
|
||||
}
|
||||
|
||||
let style = doc.defaultView.getComputedStyle(button);
|
||||
const unsubmittedStyle = doc.defaultView.getComputedStyle(reportListUnsubmitted);
|
||||
const submittedStyle = doc.defaultView.getComputedStyle(reportListSubmitted);
|
||||
Assert.notEqual(unsubmittedStyle.display, "none", "Unsubmitted report list is visible");
|
||||
Assert.notEqual(submittedStyle.display, "none", "Submitted report list is visible");
|
||||
|
||||
Assert.notEqual(style.display, "none", "Clear reports button visible");
|
||||
|
||||
let deferred = {};
|
||||
deferred.promise = new Promise(resolve => deferred.resolve = resolve);
|
||||
var observer = new content.MutationObserver(function(mutations) {
|
||||
for (let mutation of mutations) {
|
||||
if (mutation.type == "attributes" &&
|
||||
mutation.attributeName == "style") {
|
||||
observer.disconnect();
|
||||
Assert.equal(style.display, "none", "Clear reports button hidden");
|
||||
deferred.resolve();
|
||||
}
|
||||
}
|
||||
});
|
||||
observer.observe(button, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
characterData: true,
|
||||
attributeFilter: ["style"],
|
||||
});
|
||||
|
||||
button.click();
|
||||
return deferred.promise;
|
||||
const clearUnsubmittedButton = doc.getElementById("clearUnsubmittedReports");
|
||||
const clearSubmittedButton = doc.getElementById("clearSubmittedReports");
|
||||
clearUnsubmittedButton.click();
|
||||
clearSubmittedButton.click();
|
||||
}
|
||||
|
||||
var promptShown = false;
|
||||
|
@ -103,7 +85,10 @@ add_task(async function test() {
|
|||
let existing = [ file1.path, file2.path, report1.path, report2.path,
|
||||
report3.path, submitdir.path, pendingdir.path ];
|
||||
|
||||
await ContentTask.spawn(browser, null, clickClearReports);
|
||||
ContentTask.spawn(browser, null, clickClearReports);
|
||||
await BrowserTestUtils.waitForCondition(() =>
|
||||
content.document.getElementById("reportListUnsubmitted").classList.contains("hidden")
|
||||
&& content.document.getElementById("reportListSubmitted").classList.contains("hidden"));
|
||||
|
||||
for (let dir of dirs) {
|
||||
let entries = dir.directoryEntries;
|
||||
|
|
|
@ -4,16 +4,22 @@
|
|||
|
||||
crash-reports-title = Crash Reports
|
||||
|
||||
clear-all-reports-label = Remove All Reports
|
||||
delete-button-label = Clear All
|
||||
delete-confirm-title = Are you sure?
|
||||
delete-confirm-description = This will delete all reports and cannot be undone.
|
||||
delete-unsubmitted-description = This will delete all unsubmitted crash reports and cannot be undone.
|
||||
delete-submitted-description = This will remove the list of submitted crash reports but will not delete the submitted data. This cannot be undone.
|
||||
|
||||
crashes-unsubmitted-label = Unsubmitted Crash Reports
|
||||
id-heading = Report ID
|
||||
date-crashed-heading = Date Crashed
|
||||
submit-crash-button-label = Submit
|
||||
# This text is used to replace the label of the crash submit button
|
||||
# if the crash submission fails.
|
||||
submit-crash-button-failure-label = Failed
|
||||
|
||||
crashes-submitted-label = Submitted Crash Reports
|
||||
date-submitted-heading = Date Submitted
|
||||
view-crash-button-label = View
|
||||
|
||||
no-reports-label = No crash reports have been submitted.
|
||||
no-config-label = This application has not been configured to display crash reports. The preference <code>breakpad.reportURL</code> must be set.
|
||||
|
|
Загрузка…
Ссылка в новой задаче