Bug 1403130 - Support ObjectInspector-based object value grip view in ExtensionSidebar draft
authorLuca Greco <lgreco@mozilla.com>
Thu, 12 Oct 2017 16:20:39 +0200
changeset 679397 230bd47c24e9605e2abb7146cc050bf8945fc124
parent 679396 9ef4bef4655e68eff94437ad5ca2219006b5dde7
child 679398 a77d8cf437304ebe1e9cac6f5c553de0d1aee56f
push id84214
push userluca.greco@alcacoop.it
push dateThu, 12 Oct 2017 16:34:23 +0000
bugs1403130
milestone58.0a1
Bug 1403130 - Support ObjectInspector-based object value grip view in ExtensionSidebar MozReview-Commit-ID: DxU886yOCPu
devtools/client/inspector/extensions/actions/index.js
devtools/client/inspector/extensions/actions/sidebar.js
devtools/client/inspector/extensions/components/ExtensionSidebar.js
devtools/client/inspector/extensions/components/moz.build
devtools/client/inspector/extensions/extension-sidebar.js
devtools/client/inspector/extensions/reducers/sidebar.js
--- a/devtools/client/inspector/extensions/actions/index.js
+++ b/devtools/client/inspector/extensions/actions/index.js
@@ -6,12 +6,15 @@
 
 const { createEnum } = require("devtools/client/shared/enum");
 
 createEnum([
 
   // Update the extension sidebar with an object TreeView.
   "EXTENSION_SIDEBAR_OBJECT_TREEVIEW_UPDATE",
 
+  // Update the extension sidebar with an object value grip preview.
+  "EXTENSION_SIDEBAR_OBJECT_GRIP_VIEW_UPDATE",
+
   // Remove an extension sidebar from the inspector store.
   "EXTENSION_SIDEBAR_REMOVE"
 
 ], module.exports);
--- a/devtools/client/inspector/extensions/actions/sidebar.js
+++ b/devtools/client/inspector/extensions/actions/sidebar.js
@@ -1,16 +1,17 @@
 /* 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 {
   EXTENSION_SIDEBAR_OBJECT_TREEVIEW_UPDATE,
+  EXTENSION_SIDEBAR_OBJECT_GRIP_VIEW_UPDATE,
   EXTENSION_SIDEBAR_REMOVE,
 } = require("./index");
 
 module.exports = {
 
   /**
    * Update the sidebar with an object treeview.
    */
@@ -18,16 +19,28 @@ module.exports = {
     return {
       type: EXTENSION_SIDEBAR_OBJECT_TREEVIEW_UPDATE,
       sidebarId,
       object,
     };
   },
 
   /**
+   * Update the sidebar with an object actor preview.
+   */
+  updateObjectValueGripView(sidebarId, objectValueGrip, rootTitle) {
+    return {
+      type: EXTENSION_SIDEBAR_OBJECT_GRIP_VIEW_UPDATE,
+      sidebarId,
+      objectValueGrip,
+      rootTitle,
+    };
+  },
+
+  /**
    * Remove the extension sidebar from the inspector store.
    */
   removeExtensionSidebar(sidebarId) {
     return {
       type: EXTENSION_SIDEBAR_REMOVE,
       sidebarId,
     };
   }
--- a/devtools/client/inspector/extensions/components/ExtensionSidebar.js
+++ b/devtools/client/inspector/extensions/components/ExtensionSidebar.js
@@ -9,50 +9,74 @@ const {
   createClass, createFactory,
   DOM: dom,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
 
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 
 const ObjectTreeView = createFactory(require("./ObjectTreeView"));
+const ObjectValueGripView = createFactory(require("./ObjectValueGripView"));
 
 /**
  * The ExtensionSidebar is a React component with 2 supported viewMode:
- * - an ObjectTreeView UI, used to show the JS objects (used by the sidebar.setObject
- *   and sidebar.setExpression WebExtensions APIs)
- * - an ExtensionPage UI used to show an extension page (used by the sidebar.setPage
- *   WebExtensions APIs).
+ * - an ObjectTreeView UI, used to show the JS objects
+ *   (used by the sidebar.setObject WebExtensions APIs)
+ * - an ObjectValueGripView UI, used to show the objects value grips
+ *   (used by sidebar.setExpression WebExtensions APIs)
+ * - an ExtensionPage UI used to show an extension page
+ *   (used by the sidebar.setPage WebExtensions APIs).
  *
  * TODO: implement the ExtensionPage viewMode.
  */
 const ExtensionSidebar = createClass({
   displayName: "ExtensionSidebar",
 
   propTypes: {
     id: PropTypes.string.isRequired,
     extensionsSidebar: PropTypes.object.isRequired,
+    // Helpers injected as props by extension-sidebar.js.
+    serviceContainer: PropTypes.shape({
+      createObjectClient: PropTypes.func.isRequired,
+      releaseActor: PropTypes.func.isRequired,
+      highlightDomElement: PropTypes.func.isRequired,
+      unHighlightDomElement: PropTypes.func.isRequired,
+      openNodeInInspector: PropTypes.func.isRequired,
+    }).isRequired,
   },
 
   mixins: [ addons.PureRenderMixin ],
 
   render() {
-    const { id, extensionsSidebar } = this.props;
+    const {
+      id,
+      extensionsSidebar,
+      serviceContainer,
+    } = this.props;
 
     let {
       viewMode = "empty-sidebar",
-      object
+      object,
+      objectValueGrip,
+      rootTitle
     } = extensionsSidebar[id] || {};
 
     let sidebarContentEl;
 
     switch (viewMode) {
       case "object-treeview":
         sidebarContentEl = ObjectTreeView({ object });
         break;
+      case "object-value-grip-view":
+        sidebarContentEl = ObjectValueGripView({
+          objectValueGrip,
+          serviceContainer,
+          rootTitle,
+        });
+        break;
       case "empty-sidebar":
         break;
       default:
         throw new Error(`Unknown ExtensionSidebar viewMode: "${viewMode}"`);
     }
 
     const className = "devtools-monospace extension-sidebar inspector-tabpanel";
 
--- a/devtools/client/inspector/extensions/components/moz.build
+++ b/devtools/client/inspector/extensions/components/moz.build
@@ -2,9 +2,10 @@
 # vim: set filetype=python:
 # 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/.
 
 DevToolsModules(
     'ExtensionSidebar.js',
     'ObjectTreeView.js',
+    'ObjectValueGripView.js',
 )
--- a/devtools/client/inspector/extensions/extension-sidebar.js
+++ b/devtools/client/inspector/extensions/extension-sidebar.js
@@ -3,22 +3,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {
   createElement, createFactory,
 } = require("devtools/client/shared/vendor/react");
 
+const { ObjectClient } = require("devtools/shared/client/main");
+
 const { Provider } = require("devtools/client/shared/vendor/react-redux");
-
 const ExtensionSidebarComponent = createFactory(require("./components/ExtensionSidebar"));
 
 const {
   updateObjectTreeView,
+  updateObjectValueGripView,
   removeExtensionSidebar,
 } = require("./actions/sidebar");
 
 /**
  * ExtensionSidebar instances represents Inspector sidebars installed by add-ons
  * using the devtools.panels.elements.createSidebarPane WebExtensions API.
  *
  * The WebExtensions API registers the extensions' sidebars on the toolbox instance
@@ -50,16 +52,46 @@ class ExtensionSidebar {
   get provider() {
     if (!this._provider) {
       this._provider = createElement(Provider, {
         store: this.store,
         key: this.id,
         title: this.title,
       }, ExtensionSidebarComponent({
         id: this.id,
+        serviceContainer: {
+          createObjectClient: (object) => {
+            return new ObjectClient(this.inspector.toolbox.target.client, object);
+          },
+          releaseActor: (actor) => {
+            if (!actor) {
+              return;
+            }
+            this.inspector.toolbox.target.client.release(actor);
+          },
+          highlightDomElement: (grip, options = {}) => {
+            return this.inspector.toolbox.highlighterUtils
+              ? this.inspector.toolbox.highlighterUtils.highlightDomValueGrip(grip, options)
+              : null;
+          },
+          unHighlightDomElement: (forceHide = false) => {
+            return this.inspector.toolbox.highlighterUtils
+              ? this.inspector.toolbox.highlighterUtils.unhighlight(forceHide)
+              : null;
+          },
+          openNodeInInspector: async (grip) => {
+            let front = await this.inspector.toolbox.highlighterUtils.gripToNodeFront(grip);
+            let onInspectorUpdated = this.inspector.once("inspector-updated");
+            let onNodeFrontSet = this.inspector.toolbox.selection.setNodeFront(
+              front, "inspector-extension-sidebar"
+            );
+
+            return Promise.all([onNodeFrontSet, onInspectorUpdated]);
+          }
+        },
       }));
     }
 
     return this._provider;
   }
 
   /**
    * Destroy the ExtensionSidebar instance, dispatch a removeExtensionSidebar Redux action
@@ -91,11 +123,24 @@ class ExtensionSidebar {
    */
   setObject(object) {
     if (this.removed) {
       throw new Error("Unable to set an object preview on a removed ExtensionSidebar");
     }
 
     this.store.dispatch(updateObjectTreeView(this.id, object));
   }
+
+  /**
+   * Dispatch an objectPreview action to change the SidebarComponent into an
+   * ObjectPreview React Component, which shows the passed value grip
+   * in the sidebar.
+   */
+  setObjectValueGrip(objectValueGrip, rootTitle) {
+    if (this.removed) {
+      throw new Error("Unable to set an object preview on a removed ExtensionSidebar");
+    }
+
+    this.store.dispatch(updateObjectValueGripView(this.id, objectValueGrip, rootTitle));
+  }
 }
 
 module.exports = ExtensionSidebar;
--- a/devtools/client/inspector/extensions/reducers/sidebar.js
+++ b/devtools/client/inspector/extensions/reducers/sidebar.js
@@ -1,16 +1,17 @@
 /* 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 {
   EXTENSION_SIDEBAR_OBJECT_TREEVIEW_UPDATE,
+  EXTENSION_SIDEBAR_OBJECT_GRIP_VIEW_UPDATE,
   EXTENSION_SIDEBAR_REMOVE,
 } = require("../actions/index");
 
 const INITIAL_SIDEBAR = {};
 
 let reducers = {
 
   [EXTENSION_SIDEBAR_OBJECT_TREEVIEW_UPDATE](sidebar, {sidebarId, object}) {
@@ -19,16 +20,28 @@ let reducers = {
     return Object.assign({}, sidebar, {
       [sidebarId]: {
         viewMode: "object-treeview",
         object,
       }
     });
   },
 
+  [EXTENSION_SIDEBAR_OBJECT_GRIP_VIEW_UPDATE](sidebar, {sidebarId, objectValueGrip, rootTitle}) {
+    // Update the sidebar to a "object-treeview" which shows
+    // the passed object.
+    return Object.assign({}, sidebar, {
+      [sidebarId]: {
+        viewMode: "object-value-grip-view",
+        objectValueGrip,
+        rootTitle,
+      }
+    });
+  },
+
   [EXTENSION_SIDEBAR_REMOVE](sidebar, {sidebarId}) {
     // Remove the sidebar from the Redux store.
     delete sidebar[sidebarId];
     return Object.assign({}, sidebar);
   },
 
 };