Bug 1454931 - Display help screen when no service worker is available;r=sole
authorJulian Descottes <jdescottes@mozilla.com>
Mon, 19 Mar 2018 18:55:22 +0100
changeset 414832 e56c4c3f751fdf9ccbb60242e7aba379142dfb8f
parent 414831 b2174d5770ef7e79c958349fa04225c5ea4926ad
child 414834 434e9f18678ce97a0782c73eba1351b0b8216fa4
push id63021
push userjdescottes@mozilla.com
push dateFri, 20 Apr 2018 23:31:42 +0000
treeherderautoland@e56c4c3f751f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssole
bugs1454931
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1454931 - Display help screen when no service worker is available;r=sole MozReview-Commit-ID: JDPX45YIkrB
devtools/client/application/application.css
devtools/client/application/initializer.js
devtools/client/application/src/components/App.css
devtools/client/application/src/components/App.js
devtools/client/application/src/components/WorkerList.js
devtools/client/application/src/components/WorkerListEmpty.css
devtools/client/application/src/components/WorkerListEmpty.js
devtools/client/application/src/components/moz.build
--- a/devtools/client/application/application.css
+++ b/devtools/client/application/application.css
@@ -1,15 +1,16 @@
 /* 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/. */
 
 @import "resource://devtools/client/application/src/components/App.css";
 @import "resource://devtools/client/application/src/components/Worker.css";
 @import "resource://devtools/client/application/src/components/WorkerList.css";
+@import "resource://devtools/client/application/src/components/WorkerListEmpty.css";
 
 * {
   box-sizing: border-box;
 }
 
 html,
 body,
 #mount {
--- a/devtools/client/application/initializer.js
+++ b/devtools/client/application/initializer.js
@@ -31,19 +31,28 @@ window.Application = {
     this.mount = document.querySelector("#mount");
     this.toolbox = toolbox;
     this.client = toolbox.target.client;
 
     this.store = configureStore();
     this.actions = bindActionCreators(actions, this.store.dispatch);
 
     const serviceContainer = {
-      openAboutDebugging() {
+      openWebLink(url) {
         let win = toolbox.doc.defaultView.top;
-        win.openUILinkIn("about:debugging#workers", "tab", { relatedToCurrent: true });
+        win.openWebLinkIn(url, "tab", { relatedToCurrent: true });
+      },
+
+      openTrustedLink(url) {
+        let win = toolbox.doc.defaultView.top;
+        win.openTrustedLinkIn(url, "tab", { relatedToCurrent: true });
+      },
+
+      selectTool(toolId) {
+        return toolbox.selectTool(toolId);
       }
     };
 
     // Render the root Application component.
     const app = App({ client: this.client, serviceContainer });
     render(Provider({ store: this.store }, app), this.mount);
 
     this.client.addListener("workerListChanged", this.updateWorkers);
--- a/devtools/client/application/src/components/App.css
+++ b/devtools/client/application/src/components/App.css
@@ -18,16 +18,20 @@
 .application {
   height: 100%;
   padding: 0 0 0 20px;
   overflow: auto;
   display: flex;
   flex-direction: column;
 }
 
+.application.empty {
+  background-color: var(--grey-30);
+}
+
 h1 {
   font-size: 22px;
   font-weight: normal;
 }
 
 a,
 a:hover,
 a:visited {
--- a/devtools/client/application/src/components/App.js
+++ b/devtools/client/application/src/components/App.js
@@ -5,34 +5,42 @@
 "use strict";
 
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const { createFactory, Component } = require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const { div } = require("devtools/client/shared/vendor/react-dom-factories");
 
 const WorkerList = createFactory(require("./WorkerList"));
+const WorkerListEmpty = createFactory(require("./WorkerListEmpty"));
 
 /**
  * This is the main component for the application panel.
  */
 class App extends Component {
   static get propTypes() {
     return {
       client: PropTypes.object.isRequired,
       workers: PropTypes.object.isRequired,
       serviceContainer: PropTypes.object.isRequired,
     };
   }
 
   render() {
     let { workers, client, serviceContainer } = this.props;
+    const isEmpty = workers.length == 0;
 
-    return div({className: "application"},
-      WorkerList({ workers, client, serviceContainer }));
+    return (
+      div(
+        { className: `application ${isEmpty ? "empty" : ""}` },
+        isEmpty
+          ? WorkerListEmpty({ serviceContainer })
+          : WorkerList({ workers, client, serviceContainer })
+      )
+    );
   }
 }
 
 // Exports
 
 module.exports = connect(
   (state) => ({ workers: state.workers.list }),
 )(App);
--- a/devtools/client/application/src/components/WorkerList.js
+++ b/devtools/client/application/src/components/WorkerList.js
@@ -20,32 +20,35 @@ class WorkerList extends Component {
       client: PropTypes.object.isRequired,
       workers: PropTypes.object.isRequired,
       serviceContainer: PropTypes.object.isRequired,
     };
   }
 
   render() {
     const { workers, client, serviceContainer } = this.props;
-    const { openAboutDebugging } = serviceContainer;
+    const { openTrustedLink } = serviceContainer;
 
     return [
       ul({ className: "application-workers-container" },
         li({},
           h1({ className: "application-title" }, "Service Workers")
         ),
         workers.map(worker => Worker({
           client,
           debugDisabled: false,
           worker,
         }))
       ),
       div({ className: "application-aboutdebugging-plug" },
         "See about:debugging for Service Workers from other domains",
-        a({ onClick: () => openAboutDebugging() }, "Open about:debugging")
+        a(
+          { onClick: () => openTrustedLink("about:debugging#workers") },
+          "Open about:debugging"
+        )
       )
     ];
   }
 }
 
 // Exports
 
 module.exports = WorkerList;
new file mode 100644
--- /dev/null
+++ b/devtools/client/application/src/components/WorkerListEmpty.css
@@ -0,0 +1,19 @@
+/* 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/. */
+
+.worker-list-empty {
+  width: 700px;
+  line-height: 24px;
+  left: 50%;
+  top: 50%;
+  margin-top: -100px;
+  margin-left: -350px;
+  position: absolute;
+  font-size: 13px;
+}
+
+.worker-list-empty ul {
+  list-style: unset;
+  padding: 0 40px;
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/client/application/src/components/WorkerListEmpty.js
@@ -0,0 +1,88 @@
+/* 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/. */
+
+"use strict";
+
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const { Component } = require("devtools/client/shared/vendor/react");
+const { a, div, li, ul } = require("devtools/client/shared/vendor/react-dom-factories");
+const DOC_URL = "https://developer.mozilla.org/docs/Web/API/Service_Worker_API/Using_Service_Workers";
+
+/**
+ * This component displays help information when no service workers are found for the
+ * current target.
+ */
+class WorkerListEmpty extends Component {
+  static get propTypes() {
+    return {
+      serviceContainer: PropTypes.object.isRequired,
+    };
+  }
+
+  switchToConsole() {
+    this.props.serviceContainer.selectTool("webconsole");
+  }
+
+  switchToDebugger() {
+    this.props.serviceContainer.selectTool("jsdebugger");
+  }
+
+  openAboutDebugging() {
+    this.props.serviceContainer.openTrustedLink("about:debugging#workers");
+  }
+
+  openDocumentation() {
+    this.props.serviceContainer.openWebLink(DOC_URL);
+  }
+
+  render() {
+    return div(
+      { className: "worker-list-empty" },
+      div(
+        {},
+        "You need to register a Service Worker to inspect it here.",
+        a(
+          { className: "external-link", onClick: () => this.openDocumentation() },
+          "Learn More"
+        )
+      ),
+      div(
+        {},
+        `If the current page should have a service worker, ` +
+        `here are some things you can try`,
+      ),
+      ul(
+        {},
+        li(
+          {},
+          "Look for errors in the Console.",
+          a(
+            { className: "link", onClick: () => this.switchToConsole() },
+            "Open the Console"
+          )
+        ),
+        li(
+          {},
+          "Step through you Service Worker registration and look for exceptions.",
+          a(
+            { className: "link", onClick: () => this.switchToDebugger()},
+            "Open the Debugger"
+          )
+        ),
+        li(
+          {},
+          "Inspect Service Workers from other domains.",
+          a(
+            { className: "external-link", onClick: () => this.openAboutDebugging() },
+            "Open about:debugging"
+          )
+        )
+      )
+    );
+  }
+}
+
+// Exports
+
+module.exports = WorkerListEmpty;
--- a/devtools/client/application/src/components/moz.build
+++ b/devtools/client/application/src/components/moz.build
@@ -4,9 +4,11 @@
 
 DevToolsModules(
     'App.css',
     'App.js',
     'Worker.css',
     'Worker.js',
     'WorkerList.css',
     'WorkerList.js',
+    'WorkerListEmpty.css',
+    'WorkerListEmpty.js',
 )