Bug 1471795 - Part 13: Add installing form for temporary extension. r?jdescottes, r?ladybenko draft
authorDaisuke Akatsuka <dakatsuka@mozilla.com>
Thu, 19 Jul 2018 18:05:14 +0900
changeset 820262 b67a99c62c8abacddf6dce8a150f38f5a18b5742
parent 820261 b6f08ecfa40857033d353d140c4f1e19a9a06373
child 820263 020e51245bb7c04bae1190d31764bd2732ed52d3
push id116772
push userbmo:dakatsuka@mozilla.com
push dateThu, 19 Jul 2018 09:51:56 +0000
reviewersjdescottes, ladybenko
bugs1471795
milestone63.0a1
Bug 1471795 - Part 13: Add installing form for temporary extension. r?jdescottes, r?ladybenko MozReview-Commit-ID: G3EhOLzO7dn
devtools/client/aboutdebugging-new/aboutdebugging.css
devtools/client/aboutdebugging-new/src/components/DebugTargetsPane.js
devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetList.js
devtools/client/aboutdebugging-new/src/components/debugtarget/TemporaryExtensionInstaller.css
devtools/client/aboutdebugging-new/src/components/debugtarget/TemporaryExtensionInstaller.js
devtools/client/aboutdebugging-new/src/components/debugtarget/moz.build
devtools/client/aboutdebugging-new/src/runtimes/runtime.js
devtools/client/aboutdebugging-new/src/runtimes/this-firefox.js
--- a/devtools/client/aboutdebugging-new/aboutdebugging.css
+++ b/devtools/client/aboutdebugging-new/aboutdebugging.css
@@ -6,14 +6,15 @@
 @import "resource://devtools/client/themes/variables.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/App.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/DebugTargetsPane.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/RuntimeInfo.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/RuntimesPane.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetItem.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetList.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/ExtensionItem.css";
+@import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/TemporaryExtensionInstaller.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/runtime/ThisFirefoxItem.css";
 
 #mount {
   height: 100%;
   width: 100%;
 }
--- a/devtools/client/aboutdebugging-new/src/components/DebugTargetsPane.js
+++ b/devtools/client/aboutdebugging-new/src/components/DebugTargetsPane.js
@@ -9,16 +9,18 @@ const dom = require("devtools/client/sha
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
 const Runtime = require("../runtimes/runtime");
 
 const DebugTargetList = createFactory(require("./debugtarget/DebugTargetList"));
 const ExtensionItem = createFactory(require("./debugtarget/ExtensionItem"));
 const RuntimeInfo = createFactory(require("./RuntimeInfo"));
 const TabItem = createFactory(require("./debugtarget/TabItem"));
+const TemporaryExtensionInstaller =
+  createFactory(require("./debugtarget/TemporaryExtensionInstaller"));
 
 class DebugTargetsPane extends PureComponent {
   static get propTypes() {
     return {
       runtime: PropTypes.instanceOf(Runtime).isRequired,
     };
   }
 
@@ -100,16 +102,17 @@ class DebugTargetsPane extends PureCompo
       {
         className: "debug-targets-pane",
       },
       RuntimeInfo({ info }),
       DebugTargetList({
         className: "debug-target-list--temporary-extensions",
         debugTargetItemComponent: ExtensionItem,
         debugTargets: temporaryExtensions,
+        headerComponent: TemporaryExtensionInstaller,
         runtime,
         title: "Temporary Extensions",
       }),
       DebugTargetList({
         className: "debug-target-list--installed-extensions",
         debugTargetItemComponent: ExtensionItem,
         debugTargets: installedExtensions,
         runtime,
--- a/devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetList.js
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetList.js
@@ -11,40 +11,43 @@ const PropTypes = require("devtools/clie
 const Runtime = require("../../runtimes/runtime");
 
 class DebugTargetList extends PureComponent {
   static get propTypes() {
     return {
       className: PropTypes.string.isRequired,
       debugTargetItemComponent: PropTypes.any.isRequired,
       debugTargets: PropTypes.arrayOf(PropTypes.object).isRequired,
+      headerComponent: PropTypes.any,
       runtime: PropTypes.instanceOf(Runtime).isRequired,
       title: PropTypes.string.isRequired,
     };
   }
 
   render() {
     const {
       className,
       debugTargetItemComponent,
       debugTargets,
+      headerComponent,
       runtime,
       title,
     } = this.props;
 
     return dom.div(
       {
         className: `debug-target-list ${ className }`,
       },
       dom.h2(
         {
           className: `debug-target-list__title ${ className }__title`,
         },
         title
       ),
+      headerComponent ? headerComponent({ runtime }) : null,
       dom.ul(
         {
           className: `debug-target-list__ul ${ className }__ul`,
         },
         debugTargets.map(
           debugTarget => debugTargetItemComponent({ debugTarget, runtime }))
       )
     );
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/TemporaryExtensionInstaller.css
@@ -0,0 +1,7 @@
+/* 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/. */
+
+.temporary-extension-installer {
+  margin-block-end: 10px;
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/TemporaryExtensionInstaller.js
@@ -0,0 +1,46 @@
+/* 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 Runtime = require("../../runtimes/runtime");
+
+class TemporaryExtensionInstaller extends PureComponent {
+  static get propTypes() {
+    return {
+      runtime: PropTypes.instanceOf(Runtime).isRequired,
+    };
+  }
+
+  async install() {
+    const { runtime } = this.props;
+
+    try {
+      await runtime.installTemporaryExtension();
+    } catch (e) {
+      console.error(e);
+    }
+  }
+
+  render() {
+    return dom.div(
+      {
+        className: "temporary-extension-installer",
+      },
+      dom.button(
+        {
+          className: "temporary-extension-installer__install-button",
+          onClick: e => this.install()
+        },
+        "Load Temporary Add-on…"
+      )
+    );
+  }
+}
+
+module.exports = TemporaryExtensionInstaller;
--- a/devtools/client/aboutdebugging-new/src/components/debugtarget/moz.build
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/moz.build
@@ -4,10 +4,12 @@
 
 DevToolsModules(
     'DebugTargetItem.css',
     'DebugTargetItem.js',
     'DebugTargetList.css',
     'DebugTargetList.js',
     'ExtensionItem.css',
     'ExtensionItem.js',
-    'TabItem.js'
+    'TabItem.js',
+    'TemporaryExtensionInstaller.css',
+    'TemporaryExtensionInstaller.js'
 )
--- a/devtools/client/aboutdebugging-new/src/runtimes/runtime.js
+++ b/devtools/client/aboutdebugging-new/src/runtimes/runtime.js
@@ -99,16 +99,24 @@ class Runtime {
    * Subclass should override this method.
    * @param {Object} - debug target
    */
   async inspectTab(_) {
     throw new Error("Subclass of Runtime should override inspectTab()");
   }
 
   /**
+   * Install temporary extension.
+   * Subclass should override this method.
+   */
+  async installTemporaryExtension() {
+    throw new Error("Subclass of Runtime should override installTemporaryExtension()");
+  }
+
+  /**
    * Remove a tab update listener.
    * Subclass should override this method.
    * @param {function}
    */
   removeExtensionsUpdateListener(listener) {
     throw new Error("Subclass of Runtime should override " +
                     "removeExtensionsUpdateListener()");
   }
--- a/devtools/client/aboutdebugging-new/src/runtimes/this-firefox.js
+++ b/devtools/client/aboutdebugging-new/src/runtimes/this-firefox.js
@@ -1,14 +1,15 @@
 /* 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 { 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 Services = require("Services");
 
 const Runtime = require("./runtime");
@@ -84,16 +85,46 @@ class ThisFirefox extends Runtime {
       }
     });
   }
 
   async inspectTab(debugTarget) {
     window.open(`about:devtools-toolbox?type=tab&id=${ debugTarget.outerWindowID }`);
   }
 
+  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) {
+          return;
+        }
+
+        let file = fp.file;
+
+        // AddonManager.installTemporaryAddon accepts either
+        // addon directory or final xpi file.
+        if (!file.isDirectory() &&
+            !file.leafName.endsWith(".xpi") && !file.leafName.endsWith(".zip")) {
+          file = file.parent;
+        }
+
+        try {
+          await AddonManager.installTemporaryAddon(file);
+          resolve();
+        } catch (e) {
+          reject(e);
+        }
+      });
+    });
+  }
+
   removeExtensionsUpdateListener(listener) {
     const index = this.extensionsListeners.indexOf(listener);
 
     if (index > -1) {
       this.extensionsListeners.splice(index, 1);
     }
   }