Bug 1471795 - Part 16: Add action buttons. r?jdescottes, r?ladybenko draft
authorDaisuke Akatsuka <dakatsuka@mozilla.com>
Thu, 19 Jul 2018 18:40:59 +0900
changeset 820265 5e9a780dc74ccca49c16a66d2999d96e1237beac
parent 820264 18422f41f9f6667e3c959f80f335e7275a127283
child 820266 bc685ba176065e8cd4a0f358ee3e1b3fc4135d20
push id116772
push userbmo:dakatsuka@mozilla.com
push dateThu, 19 Jul 2018 09:51:56 +0000
reviewersjdescottes, ladybenko
bugs1471795
milestone63.0a1
Bug 1471795 - Part 16: Add action buttons. r?jdescottes, r?ladybenko MozReview-Commit-ID: JkPDyKtiF5j
devtools/client/aboutdebugging-new/src/components/DebugTargetsPane.js
devtools/client/aboutdebugging-new/src/components/debugtarget/ServiceWorkerItem.css
devtools/client/aboutdebugging-new/src/components/debugtarget/ServiceWorkerItem.js
devtools/client/aboutdebugging-new/src/components/debugtarget/WorkerItem.js
devtools/client/aboutdebugging-new/src/runtimes/runtime.js
devtools/client/aboutdebugging-new/src/runtimes/this-firefox.js
--- a/devtools/client/aboutdebugging-new/src/components/DebugTargetsPane.js
+++ b/devtools/client/aboutdebugging-new/src/components/DebugTargetsPane.js
@@ -149,21 +149,23 @@ class DebugTargetsPane extends PureCompo
         debugTargets: serviceWorkers,
         runtime,
         title: "Service Workers",
       }),
       DebugTargetList({
         className: "debug-target-list--shared-workers",
         debugTargetItemComponent: WorkerItem,
         debugTargets: sharedWorkers,
+        runtime,
         title: "Shared Workers",
       }),
       DebugTargetList({
         className: "debug-target-list--other-workers",
         debugTargetItemComponent: WorkerItem,
         debugTargets: otherWorkers,
+        runtime,
         title: "Other Workers",
       })
     );
   }
 }
 
 module.exports = DebugTargetsPane;
--- a/devtools/client/aboutdebugging-new/src/components/debugtarget/ServiceWorkerItem.css
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/ServiceWorkerItem.css
@@ -12,16 +12,21 @@
 }
 
 .debug-target-item__info__detail__service-worker__info__content {
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
 }
 
+.debug-target-item__info__detail__service-worker__info__unregister {
+  cursor: pointer;
+  margin-inline-start: 1ch;
+}
+
 .debug-target-item__info__detail__service-worker__status {
   border-style: solid;
   border-width: 1px;
   box-sizing: border-box;
   display: inline-block;
   font-size: 10px;
   margin-block-start: 6px;
   min-width: 50px;
--- a/devtools/client/aboutdebugging-new/src/components/debugtarget/ServiceWorkerItem.js
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/ServiceWorkerItem.js
@@ -19,16 +19,62 @@ class ServiceWorkerItem extends WorkerIt
 
   componentDidUpdate(prevProps) {
     if (prevProps.runtime !== this.props.runtime ||
         prevProps.debugTarget !== this.props.debugTarget) {
       this.updateState(this.props);
     }
   }
 
+  doInspect() {
+    if (!this.isRunning()) {
+      // If the worker is not running, we can't debug it.
+      return;
+    }
+
+    const { debugTarget, runtime } = this.props;
+    runtime.inspectWorker(debugTarget);
+  }
+
+  doPush() {
+    if (!this.isActive() || !this.isRunning()) {
+      // If the worker is not running, we can't push to it.
+      // If the worker is not active, the registration might be unavailable and the
+      // push will not succeed.
+      return;
+    }
+
+    const { debugTarget, runtime } = this.props;
+    runtime.sendRequest({
+      to: debugTarget.registrationActor,
+      type: "push"
+    });
+  }
+
+  doStart() {
+    if (!this.isActive() || this.isRunning()) {
+      // If the worker is not active or if it is already running, we can't start it.
+      return;
+    }
+
+    const { debugTarget, runtime } = this.props;
+    runtime.sendRequest({
+      to: debugTarget.registrationActor,
+      type: "start"
+    });
+  }
+
+  doUnregister() {
+    const { debugTarget, runtime } = this.props;
+    runtime.sendRequest({
+      to: debugTarget.registrationActor,
+      type: "unregister"
+    });
+  }
+
   getStatus() {
     if (this.isActive() && this.isRunning()) {
       return "running";
     } else if (this.isActive()) {
       return "stopped";
     }
     // We cannot get service worker registrations unless the registration is in
     // ACTIVE state. Unable to know the actual state ("installing", "waiting"), we
@@ -43,17 +89,48 @@ class ServiceWorkerItem extends WorkerIt
   }
 
   isActive() {
     const { debugTarget } = this.props;
     return debugTarget.active;
   }
 
   renderActionComponents() {
-    return null;
+    const inspectButton = dom.button(
+      {
+        className: "debug-target-item__actions__service-worker-inspect",
+        onClick: e => this.doInspect(),
+      },
+      "Inspect"
+    );
+
+    const pushButton = dom.button(
+      {
+        className: "debug-target-item__actions__service-worker-push",
+        onClick: e => this.doPush(),
+      },
+      "Push"
+    );
+
+    if (this.isRunning()) {
+      if (this.isActive()) {
+        return [pushButton, inspectButton];
+      }
+
+      // Only debug button is available if the service worker is not active.
+      return inspectButton;
+    }
+
+    return dom.button(
+      {
+        className: "debug-target-item__actions__service-worker-start",
+        onClick: e => this.doStart(),
+      },
+      "Start"
+    );
   }
 
   renderDetailComponents() {
     return [
       dom.div(
         {
           className: "debug-target-item__info__detail__service-worker__info",
         },
@@ -120,33 +197,50 @@ class ServiceWorkerItem extends WorkerIt
         },
         "Scope"
       ),
       dom.dd(
         {
           className: "debug-target-item__info__detail__service-worker__info__content",
           title: debugTarget.scope,
         },
-        debugTarget.scope
+        debugTarget.scope,
+        this.renderUnregisterLink()
       ),
     ];
   }
 
   renderStatus() {
     const status = this.getStatus();
 
     return dom.div(
       {
         className: "debug-target-item__info__detail__service-worker__status " +
                    `debug-target-item__info__detail__service-worker__status--${ status }`,
       },
       status
     );
   }
 
+  renderUnregisterLink() {
+    if (!this.isActive()) {
+      // If not active, there might be no registrationActor available.
+      return null;
+    }
+
+    return dom.a(
+      {
+        className: "debug-target-item__info__detail__service-worker__info__unregister",
+        onClick: e => this.doUnregister(),
+        title: "",
+      },
+      "Unregister"
+    );
+  }
+
   async updateState({ debugTarget, runtime }) {
     if (!debugTarget) {
       // A valid registrationActor is needed to retrieve the push subscription.
       return;
     }
 
     const { subscription } = await runtime.sendRequest({
       to: debugTarget.registrationActor,
--- a/devtools/client/aboutdebugging-new/src/components/debugtarget/WorkerItem.js
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/WorkerItem.js
@@ -1,28 +1,41 @@
 /* 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 dom = require("devtools/client/shared/vendor/react-dom-factories");
+
 const DebugTargetItem = require("./DebugTargetItem");
 
 class WorkerItem extends DebugTargetItem {
+  async inspect() {
+    const { debugTarget, runtime } = this.props;
+    runtime.inspectWorker(debugTarget);
+  }
+
   getIcon() {
     return "chrome://devtools/skin/images/debugging-workers.svg";
   }
 
   getName() {
     const { debugTarget } = this.props;
     return debugTarget.name;
   }
 
   renderActionComponents() {
-    return null;
+    return dom.button(
+      {
+        className: "debug-target-item__actions__worker-inspect",
+        onClick: e => this.inspect(),
+      },
+      "Inspect"
+    );
   }
 
   renderDetailComponents() {
     return null;
   }
 }
 
 module.exports = WorkerItem;
--- a/devtools/client/aboutdebugging-new/src/runtimes/runtime.js
+++ b/devtools/client/aboutdebugging-new/src/runtimes/runtime.js
@@ -108,16 +108,25 @@ class Runtime {
    * Subclass should override this method.
    * @param {Object} - debug target
    */
   async inspectTab(_) {
     throw new Error("Subclass of Runtime should override inspectTab()");
   }
 
   /**
+   * Inspect given debug target of worker which can get by getWorkers().
+   * Subclass should override this method.
+   * @param {Object} - debug target
+   */
+  async inspectWorker(_) {
+    throw new Error("Subclass of Runtime should override inspectWorker()");
+  }
+
+  /**
    * Install temporary extension.
    * Subclass should override this method.
    */
   async installTemporaryExtension() {
     throw new Error("Subclass of Runtime should override installTemporaryExtension()");
   }
 
   /**
--- a/devtools/client/aboutdebugging-new/src/runtimes/this-firefox.js
+++ b/devtools/client/aboutdebugging-new/src/runtimes/this-firefox.js
@@ -5,16 +5,17 @@
 "use strict";
 
 const { Cc, Ci } = require("chrome");
 const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
 const { BrowserToolboxProcess } =
   require("resource://devtools/client/framework/ToolboxProcess.jsm");
 const { DebuggerClient } = require("devtools/shared/client/debugger-client");
 const { DebuggerServer } = require("devtools/server/main");
+const { gDevToolsBrowser } = require("devtools/client/framework/devtools-browser");
 const Services = require("Services");
 
 const Runtime = require("./runtime");
 
 /**
  * This class represents the Firefox instance which runs in the same environment that
  * opened about:debugging.
  */
@@ -89,16 +90,20 @@ class ThisFirefox extends Runtime {
       }
     });
   }
 
   async inspectTab(debugTarget) {
     window.open(`about:devtools-toolbox?type=tab&id=${ debugTarget.outerWindowID }`);
   }
 
+  async inspectWorker(debugTarget) {
+    gDevToolsBrowser.openWorkerToolbox(this.client, debugTarget.workerTargetActor);
+  }
+
   async installTemporaryExtension() {
     return new Promise((resolve, reject) => {
       const fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
       fp.init(window,
               "Select Manifest File or Package (.xpi)",
               Ci.nsIFilePicker.modeOpen);
       fp.open(async res => {
         if (res == Ci.nsIFilePicker.returnCancel || !fp.file) {