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 414816 e56c4c3f751fdf9ccbb60242e7aba379142dfb8f
parent 414815 b2174d5770ef7e79c958349fa04225c5ea4926ad
child 414817 434e9f18678ce97a0782c73eba1351b0b8216fa4
push id33878
push userapavel@mozilla.com
push dateSat, 21 Apr 2018 09:30:31 +0000
treeherdermozilla-central@6a2fca281629 [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',
 )