diff options
Diffstat (limited to 'toolkit/crashreporter/content')
-rw-r--r-- | toolkit/crashreporter/content/crashes.js | 179 | ||||
-rw-r--r-- | toolkit/crashreporter/content/crashes.xhtml | 123 |
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> |