summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/content
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/crashreporter/content')
-rw-r--r--toolkit/crashreporter/content/crashes.js179
-rw-r--r--toolkit/crashreporter/content/crashes.xhtml123
2 files changed, 302 insertions, 0 deletions
diff --git a/toolkit/crashreporter/content/crashes.js b/toolkit/crashreporter/content/crashes.js
new file mode 100644
index 000000000..f1d3f39d9
--- /dev/null
+++ b/toolkit/crashreporter/content/crashes.js
@@ -0,0 +1,179 @@
+/* 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/. */
+
+var { classes: Cc, utils: Cu, interfaces: Ci } = Components;
+
+var reportURL;
+
+Cu.import("resource://gre/modules/CrashReports.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/osfile.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "CrashSubmit",
+ "resource://gre/modules/CrashSubmit.jsm");
+
+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() {
+
+ Services.telemetry.getHistogramById("ABOUTCRASHES_OPENED_COUNT").add(1);
+
+ var prefService = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefBranch);
+
+ try {
+ reportURL = prefService.getCharPref("breakpad.reportURL");
+ // Ignore any non http/https urls
+ 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;
+ }
+
+ const locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
+ .getService(Ci.nsIXULChromeRegistry)
+ .getSelectedLocale("global", true);
+ var dateFormatter = new Intl.DateTimeFormat(locale, { year: '2-digit',
+ month: 'numeric',
+ day: 'numeric' });
+ var timeFormatter = new Intl.DateTimeFormat(locale, { hour: 'numeric',
+ minute: 'numeric' });
+ var ios = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService);
+ var reportURI = ios.newURI(reportURL, null, null);
+ // resolving this URI relative to /report/index
+ var aboutThrottling = ios.newURI("../../about/throttling", null, reportURI);
+
+ 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);
+
+ 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) {
+ document.getElementById("unsubmitted").appendChild(row);
+ } else {
+ document.getElementById("submitted").appendChild(row);
+ }
+ }
+}
+
+var clearReports = Task.async(function*() {
+ let bundle = Services.strings.createBundle("chrome://global/locale/crashes.properties");
+
+ if (!Services.
+ prompt.confirm(window,
+ bundle.GetStringFromName("deleteconfirm.title"),
+ bundle.GetStringFromName("deleteconfirm.description"))) {
+ return;
+ }
+
+ let cleanupFolder = Task.async(function*(path, filter) {
+ let iterator = new OS.File.DirectoryIterator(path);
+ try {
+ yield iterator.forEach(Task.async(function*(aEntry) {
+ if (!filter || (yield filter(aEntry))) {
+ yield OS.File.remove(aEntry.path);
+ }
+ }));
+ } catch (e) {
+ if (!(e instanceof OS.File.Error) || !e.becauseNoSuchFile) {
+ throw e;
+ }
+ } finally {
+ iterator.close();
+ }
+ });
+
+ yield cleanupFolder(CrashReports.submittedDir.path, function*(aEntry) {
+ return aEntry.name.startsWith("bp-") && aEntry.name.endsWith(".txt");
+ });
+
+ let oneYearAgo = Date.now() - 31586000000;
+ yield cleanupFolder(CrashReports.reportsDir.path, function*(aEntry) {
+ if (!aEntry.name.startsWith("InstallTime") ||
+ aEntry.name == "InstallTime" + buildID) {
+ return false;
+ }
+
+ let date = aEntry.winLastWriteDate;
+ if (!date) {
+ let stat = yield OS.File.stat(aEntry.path);
+ date = stat.lastModificationDate;
+ }
+
+ return (date < oneYearAgo);
+ });
+
+ yield cleanupFolder(CrashReports.pendingDir.path);
+
+ document.getElementById("clear-reports").style.display = "none";
+ document.getElementById("reportList").style.display = "none";
+ document.getElementById("noReports").style.display = "block";
+});
diff --git a/toolkit/crashreporter/content/crashes.xhtml b/toolkit/crashreporter/content/crashes.xhtml
new file mode 100644
index 000000000..695320356
--- /dev/null
+++ b/toolkit/crashreporter/content/crashes.xhtml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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 PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
+[
+ <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
+ <!ENTITY % crashesDTD SYSTEM "chrome://global/locale/crashes.dtd">
+ %globalDTD;
+ %crashesDTD;
+]>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<style type="text/css">
+:root {
+ font-family: sans-serif;
+ margin: 40px auto;
+ min-width: 30em;
+ max-width: 60em;
+}
+table {
+ clear: both;
+ width: 90%;
+ margin: 0 auto;
+ padding-bottom: 2em;
+}
+th {
+ font-size: 130%;
+ text-align: left;
+ white-space: nowrap;
+}
+th[chromedir="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;
+}
+#clear-reports[chromedir="rtl"] {
+ float: left;
+}
+
+.submitting {
+ background-image: url(chrome://global/skin/icons/loading.png);
+ background-repeat: no-repeat;
+ background-position: right;
+ background-size: 16px;
+}
+
+@media (min-resolution: 1.1dppx) {
+ .submitting {
+ background-image: url(chrome://global/skin/icons/loading@2x.png);
+ }
+}
+</style>
+<link rel="stylesheet" media="screen, projection" type="text/css"
+ href="chrome://global/skin/in-content/common.css"/>
+<script type="application/javascript;version=1.8" src="chrome://global/content/crashes.js"/>
+
+<title>&crashReports.title;</title>
+</head><body onload="populateReportList()" dir="&locale.dir;">
+<button chromedir="&locale.dir;" id="clear-reports"
+ onclick="clearReports().then(null, Cu.reportError)">&clearAllReports.label;</button>
+<div id="reportList">
+ <div id="reportListUnsubmitted">
+ <h1>&crashesUnsubmitted.label;</h1>
+ <table>
+ <thead>
+ <tr>
+ <th chromedir="&locale.dir;">&id.heading;</th>
+ <th chromedir="&locale.dir;" colspan="2">&dateCrashed.heading;</th>
+ </tr>
+ </thead>
+ <tbody id="unsubmitted">
+ </tbody>
+ </table>
+ </div>
+ <div id="reportListSubmitted">
+ <h1>&crashesSubmitted.label;</h1>
+ <table>
+ <thead>
+ <tr>
+ <th chromedir="&locale.dir;">&id.heading;</th>
+ <th chromedir="&locale.dir;" colspan="2">&dateSubmitted.heading;</th>
+ </tr>
+ </thead>
+ <tbody id="submitted">
+ </tbody>
+ </table>
+ </div>
+</div>
+<p id="noReports" style="display: none">&noReports.label;</p>
+<p id="noConfig" style="display: none">&noConfig.label;</p>
+</body>
+</html>