diff --git a/devtools/client/framework/components/DebugTargetInfo.js b/devtools/client/framework/components/DebugTargetInfo.js index e096af04bd7e..d1d0e3ff2f3a 100644 --- a/devtools/client/framework/components/DebugTargetInfo.js +++ b/devtools/client/framework/components/DebugTargetInfo.js @@ -6,6 +6,8 @@ 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 @@ -15,6 +17,8 @@ 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, @@ -24,37 +28,100 @@ class DebugTargetInfo extends PureComponent { }; } - 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, deviceName, version } = deviceDescription; - const localizationType = - deviceName ? "toolbox.debugTargetInfo.runtimeLabelWithDeviceName" - : "toolbox.debugTargetInfo.runtimeLabel"; - return L10N.getFormatStr(localizationType, name, version, deviceName); + 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); + } + + 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(), ); } } diff --git a/devtools/client/framework/toolbox.js b/devtools/client/framework/toolbox.js index 57106c8f5604..2895c8d36f5b 100644 --- a/devtools/client/framework/toolbox.js +++ b/devtools/client/framework/toolbox.js @@ -76,6 +76,10 @@ loader.lazyGetter(this, "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 @@ -454,7 +458,10 @@ Toolbox.prototype = { 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. diff --git a/devtools/client/jar.mn b/devtools/client/jar.mn index fbef7b10eeb2..225ed733d79e 100644 --- a/devtools/client/jar.mn +++ b/devtools/client/jar.mn @@ -109,6 +109,8 @@ devtools.jar: 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) diff --git a/devtools/client/locales/en-US/toolbox.properties b/devtools/client/locales/en-US/toolbox.properties index 94a17f473f28..d2e5d024ea60 100644 --- a/devtools/client/locales/en-US/toolbox.properties +++ b/devtools/client/locales/en-US/toolbox.properties @@ -200,6 +200,13 @@ toolbox.options.enableNewDebugger.label=Enable new debugger frontend # 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. @@ -223,6 +230,12 @@ toolbox.debugTargetInfo.targetLabel=%1$S (%2$S) # 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. diff --git a/devtools/client/shared/remote-debugging/remote-client-manager.js b/devtools/client/shared/remote-debugging/remote-client-manager.js index 0ba4ce35c686..76ccfccb4868 100644 --- a/devtools/client/shared/remote-debugging/remote-client-manager.js +++ b/devtools/client/shared/remote-debugging/remote-client-manager.js @@ -4,6 +4,14 @@ "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. @@ -68,10 +76,31 @@ class RemoteClientManager { 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) { @@ -95,4 +124,7 @@ class RemoteClientManager { } // Expose a singleton of RemoteClientManager. -exports.remoteClientManager = new RemoteClientManager(); +module.exports = { + remoteClientManager: new RemoteClientManager(), + CONNECTION_TYPES, +}; diff --git a/devtools/client/themes/images/aboutdebugging-usb-icon.svg b/devtools/client/themes/images/aboutdebugging-usb-icon.svg new file mode 100644 index 000000000000..a30949a29839 --- /dev/null +++ b/devtools/client/themes/images/aboutdebugging-usb-icon.svg @@ -0,0 +1,6 @@ + + + + diff --git a/devtools/client/themes/images/aboutdebugging-wifi-icon.svg b/devtools/client/themes/images/aboutdebugging-wifi-icon.svg new file mode 100644 index 000000000000..49a45a1af51c --- /dev/null +++ b/devtools/client/themes/images/aboutdebugging-wifi-icon.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/devtools/client/themes/toolbox.css b/devtools/client/themes/toolbox.css index da1ed44d1f61..c6159fff937f 100644 --- a/devtools/client/themes/toolbox.css +++ b/devtools/client/themes/toolbox.css @@ -3,29 +3,55 @@ * 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 */ @@ -615,5 +641,5 @@ } .webreplay-player #overlay .tick:hover ~ .tick { - opacity: 0.5; -} \ No newline at end of file + opacity: 0.5; +}