diff --git a/browser/devtools/webide/content/newapp.js b/browser/devtools/webide/content/newapp.js
index d3f290cff7f7..49dcddd46ea6 100644
--- a/browser/devtools/webide/content/newapp.js
+++ b/browser/devtools/webide/content/newapp.js
@@ -5,8 +5,8 @@
const Cc = Components.classes;
const Cu = Components.utils;
const Ci = Components.interfaces;
-Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ZipUtils", "resource://gre/modules/ZipUtils.jsm");
@@ -100,18 +100,18 @@ function doOK() {
let projectName = document.querySelector("#project-name").value;
if (!projectName) {
- AppManager.console.error("No project name");
+ console.error("No project name");
return false;
}
if (!gTemplateList) {
- AppManager.console.error("No template index");
+ console.error("No template index");
return false;
}
let templatelistNode = document.querySelector("#templatelist");
if (templatelistNode.selectedIndex < 0) {
- AppManager.console.error("No template selected");
+ console.error("No template selected");
return false;
}
@@ -126,7 +126,7 @@ function doOK() {
fp.init(window, "Select directory where to create app directory", Ci.nsIFilePicker.modeGetFolder);
let res = fp.show();
if (res == Ci.nsIFilePicker.returnCancel) {
- AppManager.console.error("No directory selected");
+ console.error("No directory selected");
return false;
}
folder = fp.file;
@@ -139,7 +139,7 @@ function doOK() {
try {
folder.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
} catch(e) {
- AppManager.console.error(e);
+ console.error(e);
return false;
}
@@ -150,7 +150,7 @@ function doOK() {
target.append(subfolder + ".zip");
let bail = (e) => {
- AppManager.console.error(e);
+ console.error(e);
window.close();
};
diff --git a/browser/devtools/webide/content/webide.js b/browser/devtools/webide/content/webide.js
index 0099396b6919..9a25bc67d260 100644
--- a/browser/devtools/webide/content/webide.js
+++ b/browser/devtools/webide/content/webide.js
@@ -22,6 +22,7 @@ const ProjectEditor = require("projecteditor/projecteditor");
const Strings = Services.strings.createBundle("chrome://webide/content/webide.properties");
const HTML = "http://www.w3.org/1999/xhtml";
+const HELP_URL = "https://developer.mozilla.org/Firefox_OS/Using_the_App_Manager#Troubleshooting";
window.addEventListener("load", function onLoad() {
window.removeEventListener("load", onLoad);
@@ -43,8 +44,6 @@ let UI = {
this.appManagerUpdate = this.appManagerUpdate.bind(this);
AppManager.on("app-manager-update", this.appManagerUpdate);
- this.logNode = document.querySelector("#logs");
-
this.updateCommands();
this.updateRuntimeList();
@@ -64,11 +63,6 @@ let UI = {
} catch(e) {
AppManager.selectedProject = null;
}
-
- document.querySelector("#toggle-logs").addEventListener("click", function() {
- document.querySelector("#logs").classList.toggle("expand");
- UI.logNode.scrollTop = UI.logNode.scrollTopMax;
- });
},
uninit: function() {
@@ -92,12 +86,6 @@ let UI = {
appManagerUpdate: function(event, what, details) {
// Got a message from app-manager.js
switch (what) {
- case "console":
- if (details.level == "log") this.console.log(details.message);
- if (details.level == "warning") this.console.warning(details.message);
- if (details.level == "error") this.console.error(details.message);
- if (details.level == "success") this.console.success(details.message);
- break;
case "runtimelist":
this.updateRuntimeList();
break;
@@ -172,7 +160,7 @@ let UI = {
this.hidePanels();
let timeout = setTimeout(() => {
this.unbusy();
- this.console.error("Operation timeout: " + operationDescription);
+ UI.reportError("error_operationTimeout", operationDescription);
}, 30000);
this.busy();
promise.then(() => {
@@ -180,12 +168,38 @@ let UI = {
this.unbusy();
}, (e) => {
clearTimeout(timeout);
- this.console.error("Error while processing: " + operationDescription + ": " + e);
+ UI.reportError("error_operationFail", operationDescription);
+ console.error(e);
this.unbusy();
});
return promise;
},
+ reportError: function(l10nProperty, ...l10nArgs) {
+ let text;
+
+ if (l10nArgs.length > 0) {
+ text = Strings.formatStringFromName(l10nProperty, l10nArgs, l10nArgs.length);
+ } else {
+ text = Strings.GetStringFromName(l10nProperty);
+ }
+
+ console.error(text);
+
+ let buttons = [{
+ label: Strings.GetStringFromName("notification_showTroubleShooting_label"),
+ accessKey: Strings.GetStringFromName("notification_showTroubleShooting_accesskey"),
+ callback: function () {
+ Cmds.showTroubleShooting();
+ }
+ }];
+
+ let nbox = document.querySelector("#body");
+ nbox.removeAllNotifications(true);
+ nbox.appendNotification(text, "webide:errornotification", null,
+ nbox.PRIORITY_WARNING_LOW, buttons);
+ },
+
/********** RUNTIME **********/
updateRuntimeList: function() {
@@ -195,8 +209,6 @@ let UI = {
USBListNode.firstChild.remove();
}
- this.console.log("Found " + AppManager.runtimeList.usb.length + " USB devices.");
- this.console.log("Found " + AppManager.runtimeList.simulator.length + " simulators.");
for (let runtime of AppManager.runtimeList.usb) {
let panelItemNode = document.createElement("toolbarbutton");
panelItemNode.className = "panel-item runtime-panel-item-usbruntime";
@@ -229,11 +241,7 @@ let UI = {
connectToRuntime: function(runtime) {
let name = runtime.getName();
let promise = AppManager.connectToRuntime(runtime);
- this.busyUntil(promise, "connecting to runtime");
- promise.then(
- () => {this.console.success("Connected to " + name)},
- () => {this.console.error("Can't connect to " + name)});
- return promise;
+ return this.busyUntil(promise, "connecting to runtime");
},
updateRuntimeButton: function() {
@@ -303,9 +311,19 @@ let UI = {
return;
}
+ // Make sure the directory exist before we show Project Editor
+
+ let forceDetailsOnly = false;
+ if (project.type == "packaged") {
+ let directory = new FileUtils.File(project.location);
+ forceDetailsOnly = !directory.exists();
+ }
+
// Show only the details screen
- if (project.type != "packaged" || !this.isProjectEditorEnabled()) {
+ if (project.type != "packaged" ||
+ !this.isProjectEditorEnabled() ||
+ forceDetailsOnly) {
detailsIframe.removeAttribute("hidden");
projecteditorIframe.setAttribute("hidden", "true");
document.commandDispatcher.focusedElement = document.documentElement;
@@ -323,7 +341,7 @@ let UI = {
iconUrl: project.icon,
projectOverviewURL: "chrome://webide/content/details.xhtml"
});
- }, UI.console.error);
+ }, console.error);
if (project.location) {
Services.prefs.setCharPref("devtools.webide.lastprojectlocation", project.location);
@@ -439,7 +457,7 @@ let UI = {
this.closeToolboxUI();
break;
}
- } catch(e) { Cu.reportError(e); }
+ } catch(e) { console.error(e); }
},
closeToolbox: function() {
@@ -447,7 +465,7 @@ let UI = {
this.toolboxPromise.then(toolbox => {
toolbox.destroy();
this.toolboxPromise = null;
- }, this.console.error);
+ }, console.error);
}
},
@@ -488,32 +506,6 @@ let UI = {
splitter.setAttribute("hidden", "true");
document.querySelector("#action-button-debug").removeAttribute("active");
},
-
- console: {
- _log: function(msg, classname) {
- let li = document.createElementNS(HTML, "p");
- li.textContent = msg;
- li.className = classname;
- UI.logNode.appendChild(li);
- UI.logNode.scrollTop = UI.logNode.scrollTopMax;
- },
- log: function(msg) {
- UI.console._log(msg, "log");
- console.log(msg);
- },
- warning: function(msg) {
- UI.console._log(msg, "warning");
- console.warning(msg);
- },
- error: function(msg) {
- UI.console._log(msg, "error");
- console.error(msg);
- },
- success: function(msg) {
- UI.console._log(msg, "success");
- console.log(msg);
- },
- },
}
@@ -672,8 +664,6 @@ let Cmds = {
runtimeAppsNode.firstChild.remove();
}
- UI.console.log("Found " + AppManager.webAppsStore.object.all.length + " apps");
-
for (let i = 0; i < AppManager.webAppsStore.object.all.length; i++) {
let app = AppManager.webAppsStore.object.all[i];
let panelItemNode = document.createElement("toolbarbutton");
@@ -717,7 +707,7 @@ let Cmds = {
takeScreenshot: function() {
return UI.busyUntil(AppManager.deviceFront.screenshotToDataURL().then(longstr => {
return longstr.string().then(dataURL => {
- longstr.release().then(null, UI.console.error);
+ longstr.release().then(null, console.error);
UI.openInBrowser(dataURL);
});
}), "taking screenshot");
@@ -825,7 +815,7 @@ let Cmds = {
} else {
UI.toolboxPromise = AppManager.getTarget().then((target) => {
return UI.showToolbox(target);
- }, UI.console.error);
+ }, console.error);
UI.busyUntil(UI.toolboxPromise, "opening toolbox");
return UI.toolboxPromise;
}
@@ -836,6 +826,11 @@ let Cmds = {
},
toggleEditors: function() {
- // Toggle Itchpad
+ Services.prefs.setBoolPref("devtools.webide.showProjectEditor", !UI.isProjectEditorEnabled());
+ UI.openProject();
+ },
+
+ showTroubleShooting: function() {
+ UI.openInBrowser(HELP_URL);
},
}
diff --git a/browser/devtools/webide/content/webide.xul b/browser/devtools/webide/content/webide.xul
index d6b52931c2ca..74ddbfaf092b 100644
--- a/browser/devtools/webide/content/webide.xul
+++ b/browser/devtools/webide/content/webide.xul
@@ -148,18 +148,13 @@
-
+
-
+
-
-
- &logs;
-
-
diff --git a/browser/devtools/webide/locales/en-US/webide.dtd b/browser/devtools/webide/locales/en-US/webide.dtd
index bab418ba69d5..e540d55433b5 100644
--- a/browser/devtools/webide/locales/en-US/webide.dtd
+++ b/browser/devtools/webide/locales/en-US/webide.dtd
@@ -61,9 +61,6 @@
-
-
-
diff --git a/browser/devtools/webide/locales/en-US/webide.properties b/browser/devtools/webide/locales/en-US/webide.properties
index b29a57aeadfc..dd52af64e85f 100644
--- a/browser/devtools/webide/locales/en-US/webide.properties
+++ b/browser/devtools/webide/locales/en-US/webide.properties
@@ -11,3 +11,13 @@ projectButton_label=Open App
importPackagedApp_title=Select directory
importHostedApp_title=Open Hosted App
importHostedApp_header=Enter Manifest URL
+
+notification_showTroubleShooting_label=troubleshooting
+notification_showTroubleShooting_accesskey=t
+
+error_operationTimeout=Operation timed out: %1$S
+error_operationFail=Operation failed: %1$S
+error_listRunningApps=Can't get app list from device
+error_cantConnectToApp=Can't connect to app: %1$S
+error_cantInstallNotFullyConnected=Can't install project. Not fully connected.
+error_cantInstallValidationErrors=Can't install project. Validation errors.
diff --git a/browser/devtools/webide/modules/app-manager.js b/browser/devtools/webide/modules/app-manager.js
index cbd2195844d5..808f66bb5d6f 100644
--- a/browser/devtools/webide/modules/app-manager.js
+++ b/browser/devtools/webide/modules/app-manager.js
@@ -19,6 +19,8 @@ const {ConnectionManager, Connection} = require("devtools/client/connection-mana
const AppActorFront = require("devtools/app-actor-front");
const {getDeviceFront} = require("devtools/server/actors/device");
+const Strings = Services.strings.createBundle("chrome://webide/content/webide.properties");
+
exports.AppManager = AppManager = {
// FIXME: will break when devtools/app-manager will be removed:
@@ -55,26 +57,33 @@ exports.AppManager = AppManager = {
this.connection = null;
},
- console: {
- // Forward console.* calls to the UI
- log: function(msg) { AppManager.update("console", {level: "log", message: msg}); },
- warning: function(msg) { AppManager.update("console", {level: "warning", message: msg}); },
- error: function(msg) { AppManager.update("console", {level: "error", message: msg}); },
- success: function(msg) { AppManager.update("console", {level: "success", message: msg}); },
- },
-
update: function(what, details) {
// Anything we want to forward to the UI
this.emit("app-manager-update", what, details);
},
+ reportError: function(l10nProperty, ...l10nArgs) {
+ let win = Services.wm.getMostRecentWindow("devtools:webide");
+ if (win) {
+ win.UI.reportError(l10nProperty, ...l10nArgs);
+ } else {
+ let text;
+ if (l10nArgs.length > 0) {
+ text = Strings.formatStringFromName(l10nProperty, l10nArgs, l10nArgs.length);
+ } else {
+ text = Strings.GetStringFromName(l10nProperty);
+ }
+ console.error(text);
+ }
+ },
+
onConnectionChanged: function() {
if (this.connection.status == Connection.Status.DISCONNECTED) {
this.selectedRuntime = null;
}
if (this.connection.status != Connection.Status.CONNECTED) {
- AppManager.console.log("Connection status changed: " + this.connection.status);
+ console.log("Connection status changed: " + this.connection.status);
this._runningApps.clear();
this._unlistenToApps();
this._listTabsResponse = null;
@@ -101,7 +110,8 @@ exports.AppManager = AppManager = {
};
client.request(request, (res) => {
if (res.error) {
- AppManager.console.error("listRunningApps error: " + res.error);
+ this.reportError("error_listRunningApps");
+ console.error("listRunningApps error: " + res.error);
}
for (let m of res.apps) {
this._runningApps.add(m);
@@ -112,19 +122,16 @@ exports.AppManager = AppManager = {
_listenToApps: function() {
let client = this.connection.client;
client.addListener("appOpen", (type, { manifestURL }) => {
- AppManager.console.log("App open: " + manifestURL);
this._runningApps.add(manifestURL);
this.checkIfProjectIsRunning();
});
client.addListener("appClose", (type, { manifestURL }) => {
- AppManager.console.log("App close: " + manifestURL);
this._runningApps.delete(manifestURL);
this.checkIfProjectIsRunning();
});
client.addListener("appUninstall", (type, { manifestURL }) => {
- AppManager.console.log("App uninstall: " + manifestURL);
this._runningApps.delete(manifestURL);
this.checkIfProjectIsRunning();
});
@@ -142,15 +149,9 @@ exports.AppManager = AppManager = {
checkIfProjectIsRunning: function() {
if (this.selectedProject) {
if (this.isProjectRunning()) {
- AppManager.console.log("Project is running on " + this.selectedRuntime.getName());
this.update("project-is-running");
- this._notRunningLogged = false;
} else {
this.update("project-is-not-running");
- if (!this._notRunningLogged) {
- this._notRunningLogged = true;
- AppManager.console.log("Project is not running");
- }
}
}
},
@@ -163,12 +164,15 @@ exports.AppManager = AppManager = {
let actor = this._listTabsResponse.webappsActor;
let promise = AppActorFront.getTargetForApp(client, actor, manifest);
- promise.then(( ) => { AppManager.console.log("Connected to app: " + name) },
- (e) => { AppManager.console.error("Can't connect to app: " + e) });
+ promise.then(( ) => { },
+ (e) => {
+ this.reportError("error_cantConnectToApp", manifestURL);
+ console.error("Can't connect to app: " + e)
+ });
return promise;
}
- AppManager.console.error("Can't find manifestURL for selected project");
+ console.error("Can't find manifestURL for selected project");
return promise.reject();
},
@@ -196,14 +200,11 @@ exports.AppManager = AppManager = {
this._selectedProject = value;
if (this.selectedProject) {
- AppManager.console.log("New project selected: " + this.selectedProject.name);
if (this.selectedProject.type == "runtimeApp") {
this.runRuntimeApp();
} else {
this.validateProject(this.selectedProject);
}
- } else {
- AppManager.console.log("No project selected");
}
this.update("project");
@@ -243,7 +244,6 @@ exports.AppManager = AppManager = {
this.selectedRuntime = runtime;
let deferred = promise.defer();
- AppManager.console.log("Connecting to " + runtime.getName());
let onConnectedOrDisconnected = () => {
this.connection.off(Connection.Events.CONNECTED, onConnectedOrDisconnected);
this.connection.off(Connection.Events.DISCONNECTED, onConnectedOrDisconnected);
@@ -293,19 +293,19 @@ exports.AppManager = AppManager = {
let project = this.selectedProject;
if (!project || (project.type != "packaged" && project.type != "hosted")) {
- AppManager.console.error("Can't install project. Unknown type of project.");
+ console.error("Can't install project. Unknown type of project.");
return promise.reject("Can't install");
}
if (!this._listTabsResponse) {
- AppManager.console.error("Can't install project. Not fully connected.");
+ this.reportError("error_cantInstallNotFullyConnected");
return promise.reject("Can't install");
}
return this.validateProject(project).then(() => {
if (project.errorsCount > 0) {
- AppManager.console.error("Can't install project. Validation errors.");
+ this.reportError("error_cantInstallValidationErrors");
return;
}
@@ -342,15 +342,15 @@ exports.AppManager = AppManager = {
return installPromise.then(() => {
let manifest = this.getProjectManifestURL(project);
if (!this._runningApps.has(manifest)) {
- AppManager.console.log("Launching app: " + project.name);
+ console.log("Launching app: " + project.name);
AppActorFront.launchApp(client, actor, manifest);
} else {
- AppManager.console.log("Reloading app: " + project.name);
+ console.log("Reloading app: " + project.name);
AppActorFront.reloadApp(client, actor, manifest);
}
});
- }, AppManager.console.error);
+ }, console.error);
},
stopRunningApp: function() {
@@ -411,22 +411,18 @@ exports.AppManager = AppManager = {
project.warningsCount = validation.warnings.length;
project.warnings = validation.warnings;
project.validationStatus = "warning";
- AppManager.console.warning("Validation (" + project.name + "): found " + validation.warnings.length + " warnings.");
} else {
project.warnings = "";
project.warningsCount = 0;
- AppManager.console.log("Validation (" + project.name + "): no warnings found.");
}
if (validation.errors.length > 0) {
project.errorsCount = validation.errors.length;
project.errors = validation.errors;
project.validationStatus = "error";
- AppManager.console.error("Validation (" + project.name + "): found " + validation.errors.length + " errors.");
} else {
project.errors = "";
project.errorsCount = 0;
- AppManager.console.log("Validation (" + project.name + "): no errors found.");
}
if (project.warningsCount && project.errorsCount) {
@@ -442,7 +438,7 @@ exports.AppManager = AppManager = {
}
return project;
- }, AppManager.console.error);
+ }, console.error);
},
/* RUNTIME LIST */
@@ -515,7 +511,7 @@ USBRuntime.prototype = {
connect: function(connection) {
let device = Devices.getByName(this.id);
if (!device) {
- AppManager.console.error("Can't find device: " + id);
+ console.error("Can't find device: " + id);
return promise.reject();
}
return device.connect().then((port) => {
@@ -541,7 +537,7 @@ SimulatorRuntime.prototype = {
let port = ConnectionManager.getFreeTCPPort();
let simulator = Simulator.getByVersion(this.version);
if (!simulator || !simulator.launch) {
- AppManager.console.error("Can't find simulator: " + this.version);
+ console.error("Can't find simulator: " + this.version);
return promise.reject();
}
return simulator.launch({port: port}).then(() => {
diff --git a/browser/devtools/webide/test/test_basic.html b/browser/devtools/webide/test/test_basic.html
index cb4d3e7cf8ae..4e15d2a77111 100644
--- a/browser/devtools/webide/test/test_basic.html
+++ b/browser/devtools/webide/test/test_basic.html
@@ -18,21 +18,34 @@
window.onload = function() {
SimpleTest.waitForExplicitFinish();
- openWebIDE().then((win) => {
+ Task.spawn(function* () {
+ let win = yield openWebIDE();
+
ok(win, "Found a window");
ok(win.AppManager, "App Manager accessible");
let appmgr = win.AppManager;
ok(appmgr.connection, "App Manager connection ready");
ok(appmgr.runtimeList, "Runtime list ready");
ok(appmgr.webAppsStore, "WebApps store ready");
- closeWebIDE(win).then(() => {
- ok(!appmgr.connection, "App Manager connection destroyed");
- ok(!appmgr.runtimeList, "Runtime list destroyed");
- ok(!appmgr.webAppsStore, "WebApps store destroyed");
- SimpleTest.finish();
- });
- });
+ // test error reporting
+ let nbox = win.document.querySelector("#body");
+ let notification = nbox.getNotificationWithValue("webide:errornotification");
+ ok(!notification, "No notification yet");
+ let deferred = promise.defer();
+ nextTick().then(() => {
+ deferred.reject("BOOM!");
+ });
+ try {
+ yield win.UI.busyUntil(deferred.promise, "xx");
+ } catch(e) {/* This *will* fail */}
+ notification = nbox.getNotificationWithValue("webide:errornotification");
+ ok(notification, "Error has been reported");
+
+ yield closeWebIDE(win);
+
+ SimpleTest.finish();
+ });
}