Bug 1506784 - UX implementation: show debug target info in about:devtools-toolbox r=jdescottes,daisuke
☠☠ backed out by 8a2bc240e695 ☠ ☠
authorBelén Albeza <balbeza@mozilla.com>
Fri, 18 Jan 2019 02:22:43 +0000
changeset 514812 df49bc87bba17cd600ab87ccf631137648312670
parent 514811 607394a48aca3721c9386d975fc2fce29bdcba59
child 514813 6557c7c9440b7d500a2b95608b3ab78f7556cbe5
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdescottes, daisuke
bugs1506784
milestone66.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 1506784 - UX implementation: show debug target info in about:devtools-toolbox r=jdescottes,daisuke Differential Revision: https://phabricator.services.mozilla.com/D16553
devtools/client/framework/components/DebugTargetInfo.js
devtools/client/framework/toolbox.js
devtools/client/jar.mn
devtools/client/locales/en-US/toolbox.properties
devtools/client/shared/remote-debugging/remote-client-manager.js
devtools/client/themes/images/aboutdebugging-usb-icon.svg
devtools/client/themes/images/aboutdebugging-wifi-icon.svg
devtools/client/themes/toolbox.css
--- a/devtools/client/framework/components/DebugTargetInfo.js
+++ b/devtools/client/framework/components/DebugTargetInfo.js
@@ -1,62 +1,129 @@
 /* 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 { CONNECTION_TYPES } =
+  require("devtools/client/shared/remote-debugging/remote-client-manager");
 
 /**
  * This is header that should be displayed on top of the toolbox when using
  * about:devtools-toolbox.
  */
 class DebugTargetInfo extends PureComponent {
   static get propTypes() {
     return {
       deviceDescription: PropTypes.shape({
+        channel: PropTypes.string.isRequired,
+        connectionType: PropTypes.string,
         deviceName: PropTypes.string,
         name: PropTypes.string.isRequired,
         version: PropTypes.string.isRequired,
       }).isRequired,
       L10N: PropTypes.object.isRequired,
       toolbox: PropTypes.object.isRequired,
     };
   }
 
-  getTargetText() {
-    const { L10N, toolbox } = this.props;
-    const name = toolbox.target.name;
-    const type = L10N.getStr("toolbox.debugTargetInfo.type.tab");
-    return L10N.getFormatStr("toolbox.debugTargetInfo.targetLabel", name, type);
+  getRuntimeText() {
+    const { deviceDescription, L10N } = this.props;
+    const { name, version, connectionType } = deviceDescription;
+
+    return (connectionType === CONNECTION_TYPES.THIS_FIREFOX)
+      ? L10N.getFormatStr("toolbox.debugTargetInfo.runtimeLabel.thisFirefox", version)
+      : L10N.getFormatStr("toolbox.debugTargetInfo.runtimeLabel", name, version);
+  }
+
+  getAssetsForConnectionType() {
+    const { connectionType } = this.props.deviceDescription;
+
+    const BASE_IMG_URL = "chrome://devtools/skin/images/";
+    switch (connectionType) {
+      case CONNECTION_TYPES.USB:
+        return {
+          image: `${BASE_IMG_URL}aboutdebugging-usb-icon.svg`,
+          l10nId: "toolbox.debugTargetInfo.connection.usb",
+        };
+      case CONNECTION_TYPES.NETWORK:
+        return {
+          image: `${BASE_IMG_URL}aboutdebugging-globe-icon.svg`,
+          l10nId: "toolbox.debugTargetInfo.connection.network",
+        };
+    }
+  }
+
+  shallRenderConnection() {
+    const { connectionType } = this.props.deviceDescription;
+    const renderableTypes = [
+      CONNECTION_TYPES.USB,
+      CONNECTION_TYPES.NETWORK,
+    ];
+
+    return renderableTypes.includes(connectionType);
   }
 
-  getRuntimeText() {
-    const { deviceDescription, L10N } = this.props;
-    const { name, deviceName, version } = deviceDescription;
-    const localizationType =
-      deviceName ? "toolbox.debugTargetInfo.runtimeLabelWithDeviceName"
-                 : "toolbox.debugTargetInfo.runtimeLabel";
-    return L10N.getFormatStr(localizationType, name, version, deviceName);
+  renderConnection() {
+    const { connectionType } = this.props.deviceDescription;
+    const { image, l10nId } = this.getAssetsForConnectionType();
+
+    return dom.span(
+      {
+        className: "iconized-label",
+      },
+      dom.img({ src: image, alt: `${connectionType} icon`}),
+      this.props.L10N.getStr(l10nId),
+    );
+  }
+
+  renderRuntime() {
+    const { channel, deviceName } = this.props.deviceDescription;
+
+    const channelIcon =
+      (channel === "release" || channel === "beta" || channel === "aurora") ?
+      `chrome://devtools/skin/images/aboutdebugging-firefox-${ channel }.svg` :
+      "chrome://devtools/skin/images/aboutdebugging-firefox-nightly.svg";
+
+    return dom.span(
+      {
+        className: "iconized-label",
+      },
+      dom.img({ src: channelIcon, className: "channel-icon" }),
+      dom.b({ className: "ellipsis-text" }, this.getRuntimeText()),
+      dom.span({ className: "ellipsis-text" }, deviceName),
+    );
+  }
+
+  renderTarget() {
+    const title = this.props.toolbox.target.name;
+    const url = this.props.toolbox.target.url;
+    // TODO: https://bugzilla.mozilla.org/show_bug.cgi?id=1520723
+    //       Show actual favicon (currently toolbox.target.activeTab.favicon
+    //       is unpopulated)
+    const favicon = "chrome://devtools/skin/images/aboutdebugging-globe-icon.svg";
+
+    return dom.span(
+      {
+        className: "iconized-label",
+      },
+      dom.img({ src: favicon, alt: "favicon"}),
+      title ? dom.b({ className: "ellipsis-text"}, title) : null,
+      dom.span({ className: "ellipsis-text" }, url),
+    );
   }
 
   render() {
-    const { deviceDescription } = this.props;
-    const { channel } = deviceDescription;
-    const icon =
-      (channel === "release" || channel === "beta" || channel === "aurora")
-        ? `chrome://devtools/skin/images/aboutdebugging-firefox-${ channel }.svg`
-        : "chrome://devtools/skin/images/aboutdebugging-firefox-nightly.svg";
-
     return dom.header(
       {
         className: "debug-target-info",
       },
-      dom.img({ src: icon }),
-      dom.span({}, this.getRuntimeText()),
-      dom.span({ className: "target" }, this.getTargetText()),
+      this.shallRenderConnection() ? this.renderConnection() : null,
+      this.renderRuntime(),
+      this.renderTarget(),
     );
   }
 }
 
 module.exports = DebugTargetInfo;
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -71,16 +71,20 @@ loader.lazyGetter(this, "registerHarOver
   return require("devtools/client/netmonitor/src/har/toolbox-overlay").register;
 });
 
 loader.lazyGetter(this, "reloadAndRecordTab",
   () => require("devtools/client/webreplay/menu.js").reloadAndRecordTab);
 loader.lazyGetter(this, "reloadAndStopRecordingTab",
   () => require("devtools/client/webreplay/menu.js").reloadAndStopRecordingTab);
 
+loader.lazyGetter(this, "remoteClientManager", () =>
+  require("devtools/client/shared/remote-debugging/remote-client-manager.js")
+  .remoteClientManager);
+
 /**
  * A "Toolbox" is the component that holds all the tools for one specific
  * target. Visually, it's a document that includes the tools tabs and all
  * the iframes where the tool panels will be living in.
  *
  * @param {object} target
  *        The object the toolbox is debugging.
  * @param {string} selectedTool
@@ -449,17 +453,20 @@ Toolbox.prototype = {
       await this._target.attach();
 
       // Displays DebugTargetInfo which shows the basic information of debug target,
       // if `about:devtools-toolbar` URL opens directly.
       if (isToolboxURL) {
         this._showDebugTargetInfo = true;
         const deviceFront = await this.target.client.mainRoot.getFront("device");
         // DebugTargetInfo requires the device description to be rendered.
-        this._deviceDescription = await deviceFront.getDescription();
+        const description = await deviceFront.getDescription();
+        const remoteId = new this.win.URLSearchParams(this.win.location.href).get("remoteId");
+        const connectionType = remoteClientManager.getConnectionTypeByRemoteId(remoteId);
+        this._deviceDescription = Object.assign({}, description, { connectionType });
       }
 
       // Start tracking network activity on toolbox open for targets such as tabs.
       // (Workers and potentially others don't manage the console client in the target.)
       if (this._target.activeConsole) {
         await this._target.activeConsole.startListeners([
           "NetworkActivity",
         ]);
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -104,16 +104,18 @@ devtools.jar:
     skin/images/aboutdebugging-collapse-icon.svg (themes/images/aboutdebugging-collapse-icon.svg)
     skin/images/aboutdebugging-connect-icon.svg (themes/images/aboutdebugging-connect-icon.svg)
     skin/images/aboutdebugging-firefox-aurora.svg (themes/images/aboutdebugging-firefox-aurora.svg)
     skin/images/aboutdebugging-firefox-beta.svg (themes/images/aboutdebugging-firefox-beta.svg)
     skin/images/aboutdebugging-firefox-logo.svg (themes/images/aboutdebugging-firefox-logo.svg)
     skin/images/aboutdebugging-firefox-nightly.svg (themes/images/aboutdebugging-firefox-nightly.svg)
     skin/images/aboutdebugging-firefox-release.svg (themes/images/aboutdebugging-firefox-release.svg)
     skin/images/aboutdebugging-globe-icon.svg (themes/images/aboutdebugging-globe-icon.svg)
+    skin/images/aboutdebugging-wifi-icon.svg (themes/images/aboutdebugging-wifi-icon.svg)
+    skin/images/aboutdebugging-usb-icon.svg (themes/images/aboutdebugging-usb-icon.svg)
     skin/images/fox-smiling.svg (themes/images/fox-smiling.svg)
     skin/images/grid.svg (themes/images/grid.svg)
     skin/images/angle-swatch.svg (themes/images/angle-swatch.svg)
     skin/images/flexbox-swatch.svg (themes/images/flexbox-swatch.svg)
     skin/images/pseudo-class.svg (themes/images/pseudo-class.svg)
     skin/images/copy.svg (themes/images/copy.svg)
     skin/images/animation-fast-track.svg (themes/images/animation-fast-track.svg)
     skin/images/performance-details-waterfall.svg (themes/images/performance-details-waterfall.svg)
--- a/devtools/client/locales/en-US/toolbox.properties
+++ b/devtools/client/locales/en-US/toolbox.properties
@@ -195,16 +195,23 @@ toolbox.options.enableNewDebugger.label=
 # LOCALIZATION NOTE (toolbox.debugTargetInfo.runtimeLabel): This is displayed as a toolbox
 # header in about:devtools-toolbox. about:devtools-toolbox is used for instance when
 # inspecting tabs in about:debugging.
 # e.g. Mozilla Fennec (65.0a1)
 # The name of runtime: %1$S
 # The version of runtime: %2$S
 toolbox.debugTargetInfo.runtimeLabel=%1$S (%2$S)
 
+# LOCALIZATION NOTE (toolbox.debugTargetInfo.runtimeLabel.thisFirefox): this is displayed
+# as a toolbox header in about:devtools-toolbox, when inspecting the current Firefox runtime
+# (for instance, when inspecting one of its tabs in about:debugging)
+# e.g. This Firefox (65.0a1)
+# The version of runtime: %S
+toolbox.debugTargetInfo.runtimeLabel.thisFirefox=This Firefox (%S)
+
 # LOCALIZATION NOTE (toolbox.debugTargetInfo.runtimeLabelWithDeviceName): This is displayed
 # as a toolbox header in about:devtools-toolbox. about:devtools-toolbox is used for
 # instance when inspecting tabs in about:debugging.
 # e.g. Mozilla Fennec on Pixel 2 (65.0a1)
 # The name of runtime: %1$S
 # The version of runtime: %2$S
 # The device name of runtime: %3$S
 toolbox.debugTargetInfo.runtimeLabelWithDeviceName=%1$S on %3$S (%2$S)
@@ -218,16 +225,22 @@ toolbox.debugTargetInfo.runtimeLabelWith
 toolbox.debugTargetInfo.targetLabel=%1$S (%2$S)
 
 # LOCALIZATION NOTE (toolbox.debugTargetInfo.type.tab): This is displayed as a toolbox
 # header in about:devtools-toolbox. about:devtools-toolbox is used for instance when
 # inspecting tabs in about:debugging.
 # Currently, we support only this type.
 toolbox.debugTargetInfo.type.tab=tab
 
+# LOCALIZATION NOTE (toolbox.debugTargetInfo.connection.*): This is displayed in the
+# toolbox header in about:devtools-toolbox, to indicate how the connection to the
+# runtime being inspected was made.
+toolbox.debugTargetInfo.connection.usb=USB
+toolbox.debugTargetInfo.connection.network=Network
+
 # LOCALIZATION NOTE (browserToolbox.statusMessage): This is the label
 # shown next to status details when the Browser Toolbox fails to connect or
 # appears to be taking a while to do so.
 browserToolbox.statusMessage=Browser Toolbox connection status:
 
 # LOCALIZATION NOTE (toolbox.replay.jumpMessage): This is the label
 # shown in the web replay timeline marker
 toolbox.replay.jumpMessage=Jump to message %1$S
--- a/devtools/client/shared/remote-debugging/remote-client-manager.js
+++ b/devtools/client/shared/remote-debugging/remote-client-manager.js
@@ -1,14 +1,22 @@
 /* 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";
 
+/* connection types for remote clients */
+const CONNECTION_TYPES = {
+  THIS_FIREFOX: "this-firefox",
+  USB: "usb",
+  NETWORK: "network",
+  UNKNOWN: "unknown",
+};
+
 /**
  * This class is designed to be a singleton shared by all DevTools to get access to
  * existing clients created for remote debugging.
  */
 class RemoteClientManager {
   constructor() {
     this._clients = new Map();
     this._onClientClosed = this._onClientClosed.bind(this);
@@ -63,20 +71,41 @@ class RemoteClientManager {
    * Retrieve a managed client for a remote id. The remote id should have been generated
    * using getRemoteId.
    */
   getClientByRemoteId(remoteId) {
     const key = decodeURIComponent(remoteId);
     return this._clients.get(key);
   }
 
+  /**
+   * Retrieve a managed client for a remote id. The remote id should have been generated
+   * using getRemoteId.
+   */
+  getConnectionTypeByRemoteId(remoteId) {
+    if (!remoteId) {
+      return CONNECTION_TYPES.THIS_FIREFOX;
+    }
+
+    const key = decodeURIComponent(remoteId);
+    const type = this._getType(key);
+    return Object.values(CONNECTION_TYPES).includes(type)
+      ? type
+      : CONNECTION_TYPES.UNKNOWN;
+  }
+
   _getKey(id, type) {
     return id + "-" + type;
   }
 
+  _getType(key) {
+    const chunks = key.split("-");
+    return chunks[chunks.length - 1];
+  }
+
   _removeClientByKey(key) {
     const client = this._clients.get(key);
     if (client) {
       client.removeListener("closed", this._onClientClosed);
       this._clients.delete(key);
     }
   }
 
@@ -90,9 +119,12 @@ class RemoteClientManager {
 
     for (const key of closedClientKeys) {
       this._removeClientByKey(key);
     }
   }
 }
 
 // Expose a singleton of RemoteClientManager.
-exports.remoteClientManager = new RemoteClientManager();
+module.exports = {
+  remoteClientManager: new RemoteClientManager(),
+  CONNECTION_TYPES,
+};
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/aboutdebugging-usb-icon.svg
@@ -0,0 +1,6 @@
+<!-- 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/. -->
+<svg data-name="usb" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
+  <path fill="context-fill" d="M13.5 4h-2a.5.5 0 0 0-.5.5v2a.5.5 0 0 0 .5.5h.44c-.17.63-.69.8-1.56 1A4.76 4.76 0 0 0 9 8.53V4h1.07a.46.46 0 0 0 .37-.74L8.37.5a.46.46 0 0 0-.74 0L5.56 3.26a.46.46 0 0 0 .37.74H7v6.53A4.76 4.76 0 0 0 5.62 10C4.71 9.79 4.17 9.61 4 8.9a1.5 1.5 0 1 0-2-1.4 1.49 1.49 0 0 0 1 1.42c.2 1.51 1.42 1.84 2.34 2.07s1.53.43 1.6 1.3a2 2 0 1 0 2 0V10.5C9 9.44 9.56 9.25 10.62 9s2.1-.54 2.33-2h.55a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 0-.5-.5z" />
+</svg>
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/aboutdebugging-wifi-icon.svg
@@ -0,0 +1,9 @@
+<!-- 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/. -->
+<svg data-name="wifi" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
+  <path fill="context-fill" d="M15 6.24a1 1 0 0 1-.58-.18 10.94 10.94 0 0 0-12.78 0A1 1 0 0 1 .45 4.43a12.94 12.94 0 0 1 15.1 0 1 1 0 0 1 .23 1.4 1 1 0 0 1-.78.41z"/>
+  <path fill="context-fill" d="M9.74 13.56a1 1 0 0 1-.58-.18 2 2 0 0 0-2.32 0 1 1 0 0 1-1.16-1.63 4 4 0 0 1 4.64 0 1 1 0 0 1 .23 1.4 1 1 0 0 1-.81.41z"/>
+  <path fill="context-fill" d="M11.48 11.12a1 1 0 0 1-.58-.19 5.05 5.05 0 0 0-5.8 0 1 1 0 1 1-1.17-1.62 7.1 7.1 0 0 1 8.14 0 1 1 0 0 1 .23 1.4 1 1 0 0 1-.82.41z"/>
+  <path fill="context-fill" d="M13.23 8.68a1 1 0 0 1-.59-.18 8.06 8.06 0 0 0-9.28 0A1 1 0 0 1 2 8.26a1 1 0 0 1 .23-1.39 10 10 0 0 1 11.62 0A1 1 0 0 1 14 8.26a1 1 0 0 1-.77.42z"/>
+</svg>
--- a/devtools/client/themes/toolbox.css
+++ b/devtools/client/themes/toolbox.css
@@ -1,36 +1,62 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* 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/. */
 
 /*
+* Utils
+*/
+
+/* text that needs to be cut with … */
+.ellipsis-text {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+/*
  *  Debug Target Info layout
- *  +------+-------------------+------------------+
- *  | icon | runtime info text | target info text |
- *  | 32px |        auto       |        1fr       |
- *  +------+-------------------+------------------+
+ *  +------------+--------------+------------------------+
+ *  | connection | runtime info | target info icon + text |
+ *  +------------+--------------+------------------------+
  */
 .debug-target-info {
-  display: grid;
-  grid-template-columns: 32px auto 1fr;
-  grid-column-gap: 8px;
-  align-items: center;
+  display: flex;
   background: var(--theme-tab-toolbar-background);
   border-bottom: 1px solid var(--theme-splitter-color);
-  padding-bottom: 4px;
-  padding-left: 12px;
-  padding-top: 4px;
-  font-size: 1.46em;
+  padding: 4px 0;
+  font-size: 1.2em;
   color: var(--theme-toolbar-color);
 }
 
-.debug-target-info .target {
-  font-weight: lighter;
+/*
+ *  Debug Target labels with icon layout
+ *  +------+------------------------+---------------+
+ *  | icon | label text (bold)      | optional text |
+ *  | 20px |     max-content        | max-content   |
+ *  +------+------------------------+---------------+
+ */
+.debug-target-info .iconized-label {
+  display: grid;
+  grid-template-columns: 20px auto auto;
+  grid-column-gap: 8px;
+  align-items: center;
+  padding: 0 24px;
+  white-space: nowrap;
+}
+
+.debug-target-info .iconized-label:not(:last-child) {
+  border-right: 1px solid var(--theme-splitter-color);
+}
+
+.debug-target-info img {
+  -moz-context-properties: fill, stroke;
+  fill: var(--theme-toolbar-icon-color);
 }
 
 /* Toolbox tabbar */
 
 .devtools-tabbar {
   -moz-appearance: none;
   /* For narrow devtool width, we define the each column width of tabbar.
     Defined layout is as follow:
@@ -610,10 +636,10 @@
   opacity: 1;
 }
 
 .webreplay-player #overlay .tick {
   opacity: 0.5;
 }
 
 .webreplay-player #overlay .tick:hover ~ .tick {
- opacity: 0.5; 
-}
\ No newline at end of file
+  opacity: 0.5;
+}