Bug 1477602 - Part 4: Implement action buttons for worker. r=ladybenko
authorDaisuke Akatsuka <dakatsuka@mozilla.com>
Fri, 17 Aug 2018 09:58:52 +0900
changeset 491028 ab2638b0ed51338efd498612dfcf3c20df219588
parent 491027 3cab1552392997546f16cd0a087cbbeeb63716de
child 491029 d5ea1a53fa039c2a8f38c65b662c1560fa10d53a
push id1815
push userffxbld-merge
push dateMon, 15 Oct 2018 10:40:45 +0000
treeherdermozilla-release@18d4c09e9378 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersladybenko
bugs1477602
milestone63.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 1477602 - Part 4: Implement action buttons for worker. r=ladybenko Differential Revision: https://phabricator.services.mozilla.com/D3755 Depends on D3754
devtools/client/aboutdebugging-new/src/actions/runtime.js
devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetItem.js
devtools/client/aboutdebugging-new/src/components/debugtarget/InspectAction.js
devtools/client/aboutdebugging-new/src/components/debugtarget/ServiceWorkerAction.js
devtools/client/aboutdebugging-new/src/components/debugtarget/TemporaryExtensionAction.js
devtools/client/aboutdebugging-new/src/components/debugtarget/moz.build
devtools/client/aboutdebugging-new/src/reducers/runtime-state.js
--- a/devtools/client/aboutdebugging-new/src/actions/runtime.js
+++ b/devtools/client/aboutdebugging-new/src/actions/runtime.js
@@ -5,16 +5,17 @@
 "use strict";
 
 const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
 const { BrowserToolboxProcess } =
   require("resource://devtools/client/framework/ToolboxProcess.jsm");
 const { Cc, Ci } = require("chrome");
 const { DebuggerClient } = require("devtools/shared/client/debugger-client");
 const { DebuggerServer } = require("devtools/server/main");
+const { gDevToolsBrowser } = require("devtools/client/framework/devtools-browser");
 
 const {
   CONNECT_RUNTIME_FAILURE,
   CONNECT_RUNTIME_START,
   CONNECT_RUNTIME_SUCCESS,
   DEBUG_TARGETS,
   DISCONNECT_RUNTIME_FAILURE,
   DISCONNECT_RUNTIME_START,
@@ -66,36 +67,49 @@ function disconnectRuntime() {
       dispatch({ type: DISCONNECT_RUNTIME_SUCCESS });
     } catch (e) {
       dispatch({ type: DISCONNECT_RUNTIME_FAILURE, error: e.message });
     }
   };
 }
 
 function inspectDebugTarget(type, id) {
-  if (type === DEBUG_TARGETS.TAB) {
-    window.open(`about:devtools-toolbox?type=tab&id=${ id }`);
-  } else if (type === DEBUG_TARGETS.EXTENSION) {
-    // Close previous addon debugging toolbox.
-    if (browserToolboxProcess) {
-      browserToolboxProcess.close();
-    }
+  return async (_, getState) => {
+    switch (type) {
+      case DEBUG_TARGETS.TAB: {
+        // Open tab debugger in new window.
+        window.open(`about:devtools-toolbox?type=tab&id=${ id }`);
+        break;
+      }
+      case DEBUG_TARGETS.EXTENSION: {
+        // Close current debugging toolbox and open a new one.
+        if (browserToolboxProcess) {
+          browserToolboxProcess.close();
+        }
 
-    browserToolboxProcess = BrowserToolboxProcess.init({
-      addonID: id,
-      onClose: () => {
-        browserToolboxProcess = null;
+        browserToolboxProcess = BrowserToolboxProcess.init({
+          addonID: id,
+          onClose: () => {
+            browserToolboxProcess = null;
+          }
+        });
+        break;
       }
-    });
-  } else {
-    console.error(`Failed to inspect the debug target of type: ${ type } id: ${ id }`);
-  }
+      case DEBUG_TARGETS.WORKER: {
+        // Open worker toolbox in new window.
+        gDevToolsBrowser.openWorkerToolbox(getState().runtime.client, id);
+        break;
+      }
 
-  // We cancel the redux flow here since the inspection does not need to update the state.
-  return () => {};
+      default: {
+        console.error("Failed to inspect the debug target of " +
+                      `type: ${ type } id: ${ id }`);
+      }
+    }
+  };
 }
 
 function installTemporaryExtension() {
   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) {
       return;
@@ -115,16 +129,28 @@ function installTemporaryExtension() {
     } catch (e) {
       console.error(e);
     }
   });
 
   return () => {};
 }
 
+function pushServiceWorker(actor) {
+  return async (_, getState) => {
+    const client = getState().runtime.client;
+
+    try {
+      await client.request({ to: actor, type: "push" });
+    } catch (e) {
+      console.error(e);
+    }
+  };
+}
+
 function reloadTemporaryExtension(actor) {
   return async (_, getState) => {
     const client = getState().runtime.client;
 
     try {
       await client.request({ to: actor, type: "reload" });
     } catch (e) {
       console.error(e);
@@ -205,19 +231,33 @@ function requestWorkers() {
         sharedWorkers,
       });
     } catch (e) {
       dispatch({ type: REQUEST_WORKERS_FAILURE, error: e.message });
     }
   };
 }
 
+function startServiceWorker(actor) {
+  return async (_, getState) => {
+    const client = getState().runtime.client;
+
+    try {
+      await client.request({ to: actor, type: "start" });
+    } catch (e) {
+      console.error(e);
+    }
+  };
+}
+
 module.exports = {
   connectRuntime,
   disconnectRuntime,
   inspectDebugTarget,
   installTemporaryExtension,
+  pushServiceWorker,
   reloadTemporaryExtension,
   removeTemporaryExtension,
   requestTabs,
   requestExtensions,
   requestWorkers,
+  startServiceWorker,
 };
--- a/devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetItem.js
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetItem.js
@@ -4,54 +4,45 @@
 
 "use strict";
 
 const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
 const ExtensionDetail = createFactory(require("./ExtensionDetail"));
+const InspectAction = createFactory(require("./InspectAction"));
+const ServiceWorkerAction = createFactory(require("./ServiceWorkerAction"));
 const TabDetail = createFactory(require("./TabDetail"));
 const TemporaryExtensionAction = createFactory(require("./TemporaryExtensionAction"));
 const WorkerDetail = createFactory(require("./WorkerDetail"));
 
-const Actions = require("../../actions/index");
 const { DEBUG_TARGETS } = require("../../constants");
 
 /**
  * This component displays debug target.
  */
 class DebugTargetItem extends PureComponent {
   static get propTypes() {
     return {
       dispatch: PropTypes.func.isRequired,
       target: PropTypes.object.isRequired,
     };
   }
 
-  inspect() {
-    const { dispatch, target } = this.props;
-    dispatch(Actions.inspectDebugTarget(target.type, target.id));
-  }
-
   renderAction() {
     const { dispatch, target } = this.props;
 
-    return dom.div(
-      {},
-      dom.button(
-        {
-          onClick: e => this.inspect(),
-          className: "aboutdebugging-button",
-        },
-        "Inspect"
-      ),
-      target.details.temporarilyInstalled
-        ? TemporaryExtensionAction({ dispatch, target }) : null,
-    );
+    if (target.details.temporarilyInstalled) {
+      return TemporaryExtensionAction({ dispatch, target });
+    } else if (target.details.status) {
+      return ServiceWorkerAction({ dispatch, target });
+    }
+
+    return InspectAction({ dispatch, target });
   }
 
   renderDetail() {
     const { target } = this.props;
 
     switch (target.type) {
       case DEBUG_TARGETS.EXTENSION:
         return ExtensionDetail({ target });
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/InspectAction.js
@@ -0,0 +1,40 @@
+/* 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 { PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const Actions = require("../../actions/index");
+
+/**
+ * This component provides inspect button.
+ */
+class InspectAction extends PureComponent {
+  static get propTypes() {
+    return {
+      dispatch: PropTypes.func.isRequired,
+      target: PropTypes.object.isRequired,
+    };
+  }
+
+  inspect() {
+    const { dispatch, target } = this.props;
+    dispatch(Actions.inspectDebugTarget(target.type, target.id));
+  }
+
+  render() {
+    return dom.button(
+      {
+        onClick: e => this.inspect(),
+        className: "aboutdebugging-button",
+      },
+      "Inspect"
+    );
+  }
+}
+
+module.exports = InspectAction;
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/ServiceWorkerAction.js
@@ -0,0 +1,70 @@
+/* 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 { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const InspectAction = createFactory(require("./InspectAction"));
+
+const Actions = require("../../actions/index");
+
+/**
+ * This component displays buttons for service worker.
+ */
+class ServiceWorkerAction extends PureComponent {
+  static get propTypes() {
+    return {
+      dispatch: PropTypes.func.isRequired,
+      target: PropTypes.object.isRequired,
+    };
+  }
+
+  push() {
+    const { dispatch, target } = this.props;
+    dispatch(Actions.pushServiceWorker(target.id));
+  }
+
+  start() {
+    const { dispatch, target } = this.props;
+    dispatch(Actions.startServiceWorker(target.details.registrationActor));
+  }
+
+  _renderAction() {
+    const { dispatch, target } = this.props;
+    const { isActive, isRunning } = target.details;
+
+    if (!isRunning) {
+      return this._renderButton("Start", this.start.bind(this));
+    }
+
+    if (!isActive) {
+      // Only debug button is available if the service worker is not active.
+      return InspectAction({ dispatch, target });
+    }
+
+    return [
+      this._renderButton("Push", this.push.bind(this)),
+      InspectAction({ dispatch, target }),
+    ];
+  }
+
+  _renderButton(label, onClick) {
+    return dom.button(
+      {
+        className: "aboutdebugging-button",
+        onClick: e => onClick(),
+      },
+      label,
+    );
+  }
+
+  render() {
+    return dom.div({}, this._renderAction());
+  }
+}
+
+module.exports = ServiceWorkerAction;
--- a/devtools/client/aboutdebugging-new/src/components/debugtarget/TemporaryExtensionAction.js
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/TemporaryExtensionAction.js
@@ -1,22 +1,24 @@
 /* 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 { PureComponent } = require("devtools/client/shared/vendor/react");
+const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
+const InspectAction = createFactory(require("./InspectAction"));
+
 const Actions = require("../../actions/index");
 
 /**
- * This component provides components that reload/remove temporary extension.
+ * This component provides components that inspect/reload/remove temporary extension.
  */
 class TemporaryExtensionAction extends PureComponent {
   static get propTypes() {
     return {
       dispatch: PropTypes.func.isRequired,
       target: PropTypes.object.isRequired,
     };
   }
@@ -27,28 +29,32 @@ class TemporaryExtensionAction extends P
   }
 
   remove() {
     const { dispatch, target } = this.props;
     dispatch(Actions.removeTemporaryExtension(target.id));
   }
 
   render() {
-    return [
+    const { dispatch, target } = this.props;
+
+    return dom.div(
+      {},
+      InspectAction({ dispatch, target }),
       dom.button(
         {
           className: "aboutdebugging-button",
           onClick: e => this.reload()
         },
         "Reload",
       ),
       dom.button(
         {
           className: "aboutdebugging-button",
           onClick: e => this.remove()
         },
         "Remove",
       ),
-    ];
+    );
   }
 }
 
 module.exports = TemporaryExtensionAction;
--- a/devtools/client/aboutdebugging-new/src/components/debugtarget/moz.build
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/moz.build
@@ -5,14 +5,16 @@
 DevToolsModules(
     'DebugTargetItem.css',
     'DebugTargetItem.js',
     'DebugTargetList.css',
     'DebugTargetList.js',
     'DebugTargetPane.js',
     'ExtensionDetail.css',
     'ExtensionDetail.js',
+    'InspectAction.js',
+    'ServiceWorkerAction.js',
     'TabDetail.js',
     'TemporaryExtensionAction.js',
     'TemporaryExtensionInstaller.js',
     'WorkerDetail.css',
     'WorkerDetail.js',
 )
--- a/devtools/client/aboutdebugging-new/src/reducers/runtime-state.js
+++ b/devtools/client/aboutdebugging-new/src/reducers/runtime-state.js
@@ -120,47 +120,56 @@ function toTabComponentData(tabs) {
       type,
       details: {
         url,
       },
     };
   });
 }
 
-function getServiceWorkerStatus(worker) {
-  if (worker.active && !!worker.workerTargetActor) {
+function getServiceWorkerStatus(isActive, isRunning) {
+  if (isActive && isRunning) {
     return SERVICE_WORKER_STATUSES.RUNNING;
-  } else if (worker.active) {
+  } else if (isActive) {
     return SERVICE_WORKER_STATUSES.STOPPED;
   }
   // We cannot get service worker registrations unless the registration is in
   // ACTIVE state. Unable to know the actual state ("installing", "waiting"), we
   // display a custom state "registering" for now. See Bug 1153292.
   return SERVICE_WORKER_STATUSES.REGISTERING;
 }
 
 function toWorkerComponentData(workers, isServiceWorker) {
   return workers.map(worker => {
     const type = DEBUG_TARGETS.WORKER;
+    const id = worker.workerTargetActor;
     const icon = "chrome://devtools/skin/images/debugging-workers.svg";
-    let { fetch, name, scope } = worker;
+    let { fetch, name, registrationActor, scope } = worker;
+    let isActive = false;
+    let isRunning = false;
     let status = null;
 
     if (isServiceWorker) {
       fetch = fetch ? SERVICE_WORKER_FETCH_STATES.LISTENING
                     : SERVICE_WORKER_FETCH_STATES.NOT_LISTENING;
-      status = getServiceWorkerStatus(worker);
+      isActive = worker.active;
+      isRunning = !!worker.workerTargetActor;
+      status = getServiceWorkerStatus(isActive, isRunning);
     }
 
     return {
       name,
       icon,
+      id,
       type,
       details: {
         fetch,
+        isActive,
+        isRunning,
+        registrationActor,
         scope,
         status,
       },
     };
   });
 }
 
 module.exports = {