summaryrefslogtreecommitdiffstats
path: root/devtools/client/aboutdebugging/src/components/sidebar
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/aboutdebugging/src/components/sidebar')
-rw-r--r--devtools/client/aboutdebugging/src/components/sidebar/RefreshDevicesButton.js46
-rw-r--r--devtools/client/aboutdebugging/src/components/sidebar/Sidebar.css41
-rw-r--r--devtools/client/aboutdebugging/src/components/sidebar/Sidebar.js263
-rw-r--r--devtools/client/aboutdebugging/src/components/sidebar/SidebarFixedItem.css29
-rw-r--r--devtools/client/aboutdebugging/src/components/sidebar/SidebarFixedItem.js60
-rw-r--r--devtools/client/aboutdebugging/src/components/sidebar/SidebarItem.css53
-rw-r--r--devtools/client/aboutdebugging/src/components/sidebar/SidebarItem.js81
-rw-r--r--devtools/client/aboutdebugging/src/components/sidebar/SidebarRuntimeItem.css41
-rw-r--r--devtools/client/aboutdebugging/src/components/sidebar/SidebarRuntimeItem.js221
-rw-r--r--devtools/client/aboutdebugging/src/components/sidebar/moz.build11
10 files changed, 846 insertions, 0 deletions
diff --git a/devtools/client/aboutdebugging/src/components/sidebar/RefreshDevicesButton.js b/devtools/client/aboutdebugging/src/components/sidebar/RefreshDevicesButton.js
new file mode 100644
index 0000000000..0db090364e
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/components/sidebar/RefreshDevicesButton.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 {
+ createFactory,
+ PureComponent,
+} = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+
+const FluentReact = require("devtools/client/shared/vendor/fluent-react");
+const Localized = createFactory(FluentReact.Localized);
+
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const Actions = require("devtools/client/aboutdebugging/src/actions/index");
+
+class RefreshDevicesButton extends PureComponent {
+ static get propTypes() {
+ return {
+ dispatch: PropTypes.func.isRequired,
+ isScanning: PropTypes.bool.isRequired,
+ };
+ }
+
+ refreshDevices() {
+ this.props.dispatch(Actions.scanUSBRuntimes());
+ }
+
+ render() {
+ return Localized(
+ { id: "about-debugging-refresh-usb-devices-button" },
+ dom.button(
+ {
+ className: "default-button qa-refresh-devices-button",
+ disabled: this.props.isScanning,
+ onClick: () => this.refreshDevices(),
+ },
+ "Refresh devices"
+ )
+ );
+ }
+}
+
+module.exports = RefreshDevicesButton;
diff --git a/devtools/client/aboutdebugging/src/components/sidebar/Sidebar.css b/devtools/client/aboutdebugging/src/components/sidebar/Sidebar.css
new file mode 100644
index 0000000000..5e40c7741f
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/components/sidebar/Sidebar.css
@@ -0,0 +1,41 @@
+/* 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/. */
+
+.sidebar {
+ display: grid;
+ grid-template-rows: auto auto;
+}
+
+.sidebar__label {
+ color: var(--grey-50);
+ display: block;
+ padding: 12px 0;
+ text-align: center;
+ font-size: var(--message-font-size);
+}
+
+.sidebar__adb-status {
+ margin-block-end: calc(var(--base-unit) * 2);
+}
+
+.sidebar__refresh-usb {
+ text-align: center;
+}
+
+.sidebar__footer {
+ align-self: flex-end;
+}
+
+.sidebar__footer__support-help {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ column-gap: calc(var(--base-unit) * 4);
+ height: 100%;
+}
+
+.sidebar__footer__icon {
+ width: calc(var(--base-unit) * 4);
+ height: calc(var(--base-unit) * 4);
+}
diff --git a/devtools/client/aboutdebugging/src/components/sidebar/Sidebar.js b/devtools/client/aboutdebugging/src/components/sidebar/Sidebar.js
new file mode 100644
index 0000000000..8901674178
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/components/sidebar/Sidebar.js
@@ -0,0 +1,263 @@
+/* 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 FluentReact = require("devtools/client/shared/vendor/fluent-react");
+const Localized = createFactory(FluentReact.Localized);
+
+const {
+ ICON_LABEL_LEVEL,
+ PAGE_TYPES,
+ RUNTIMES,
+} = require("devtools/client/aboutdebugging/src/constants");
+const Types = require("devtools/client/aboutdebugging/src/types/index");
+loader.lazyRequireGetter(
+ this,
+ "ADB_ADDON_STATES",
+ "devtools/client/shared/remote-debugging/adb/adb-addon",
+ true
+);
+
+const IconLabel = createFactory(
+ require("devtools/client/aboutdebugging/src/components/shared/IconLabel")
+);
+const SidebarItem = createFactory(
+ require("devtools/client/aboutdebugging/src/components/sidebar/SidebarItem")
+);
+const SidebarFixedItem = createFactory(
+ require("devtools/client/aboutdebugging/src/components/sidebar/SidebarFixedItem")
+);
+const SidebarRuntimeItem = createFactory(
+ require("devtools/client/aboutdebugging/src/components/sidebar/SidebarRuntimeItem")
+);
+const RefreshDevicesButton = createFactory(
+ require("devtools/client/aboutdebugging/src/components/sidebar/RefreshDevicesButton")
+);
+const FIREFOX_ICON =
+ "chrome://devtools/skin/images/aboutdebugging-firefox-logo.svg";
+const CONNECT_ICON = "chrome://devtools/skin/images/settings.svg";
+const GLOBE_ICON =
+ "chrome://devtools/skin/images/aboutdebugging-globe-icon.svg";
+const USB_ICON =
+ "chrome://devtools/skin/images/aboutdebugging-connect-icon.svg";
+
+class Sidebar extends PureComponent {
+ static get propTypes() {
+ return {
+ adbAddonStatus: Types.adbAddonStatus,
+ className: PropTypes.string,
+ dispatch: PropTypes.func.isRequired,
+ isAdbReady: PropTypes.bool.isRequired,
+ isScanningUsb: PropTypes.bool.isRequired,
+ networkRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
+ selectedPage: Types.page,
+ selectedRuntimeId: PropTypes.string,
+ usbRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
+ };
+ }
+
+ renderAdbStatus() {
+ const isUsbEnabled =
+ this.props.isAdbReady &&
+ this.props.adbAddonStatus === ADB_ADDON_STATES.INSTALLED;
+ const localizationId = isUsbEnabled
+ ? "about-debugging-sidebar-usb-enabled"
+ : "about-debugging-sidebar-usb-disabled";
+ return IconLabel(
+ {
+ level: isUsbEnabled ? ICON_LABEL_LEVEL.OK : ICON_LABEL_LEVEL.INFO,
+ },
+ Localized(
+ {
+ id: localizationId,
+ },
+ dom.span(
+ {
+ className: "qa-sidebar-usb-status",
+ },
+ localizationId
+ )
+ )
+ );
+ }
+
+ renderDevicesEmpty() {
+ return SidebarItem(
+ {},
+ Localized(
+ {
+ id: "about-debugging-sidebar-no-devices",
+ },
+ dom.aside(
+ {
+ className: "sidebar__label qa-sidebar-no-devices",
+ },
+ "No devices discovered"
+ )
+ )
+ );
+ }
+
+ renderDevices() {
+ const { networkRuntimes, usbRuntimes } = this.props;
+
+ // render a "no devices" messages when the lists are empty
+ if (!networkRuntimes.length && !usbRuntimes.length) {
+ return this.renderDevicesEmpty();
+ }
+ // render all devices otherwise
+ return [
+ ...this.renderRuntimeItems(GLOBE_ICON, networkRuntimes),
+ ...this.renderRuntimeItems(USB_ICON, usbRuntimes),
+ ];
+ }
+
+ renderRuntimeItems(icon, runtimes) {
+ const { dispatch, selectedPage, selectedRuntimeId } = this.props;
+
+ return runtimes.map(runtime => {
+ const keyId = `${runtime.type}-${runtime.id}`;
+ const runtimeHasDetails = !!runtime.runtimeDetails;
+ const isSelected =
+ selectedPage === PAGE_TYPES.RUNTIME && runtime.id === selectedRuntimeId;
+
+ let name = runtime.name;
+ if (runtime.type === RUNTIMES.USB && runtimeHasDetails) {
+ // Update the name to be same to the runtime page.
+ name = runtime.runtimeDetails.info.name;
+ }
+
+ return SidebarRuntimeItem({
+ deviceName: runtime.extra.deviceName,
+ dispatch,
+ icon,
+ key: keyId,
+ isConnected: runtimeHasDetails,
+ isConnecting: runtime.isConnecting,
+ isConnectionFailed: runtime.isConnectionFailed,
+ isConnectionNotResponding: runtime.isConnectionNotResponding,
+ isConnectionTimeout: runtime.isConnectionTimeout,
+ isSelected,
+ isUnavailable: runtime.isUnavailable,
+ isUnplugged: runtime.isUnplugged,
+ name,
+ runtimeId: runtime.id,
+ });
+ });
+ }
+
+ renderFooter() {
+ const HELP_ICON_SRC = "chrome://global/skin/icons/help.svg";
+ const SUPPORT_URL =
+ "https://developer.mozilla.org/docs/Tools/about:debugging";
+
+ return dom.footer(
+ {
+ className: "sidebar__footer",
+ },
+ dom.ul(
+ {},
+ SidebarItem(
+ {
+ className: "sidebar-item--condensed",
+ to: SUPPORT_URL,
+ },
+ dom.span(
+ {
+ className: "sidebar__footer__support-help",
+ },
+ Localized(
+ {
+ id: "about-debugging-sidebar-support-icon",
+ attrs: {
+ alt: true,
+ },
+ },
+ dom.img({
+ className: "sidebar__footer__icon",
+ src: HELP_ICON_SRC,
+ })
+ ),
+ Localized(
+ {
+ id: "about-debugging-sidebar-support",
+ },
+ dom.span({}, "about-debugging-sidebar-support")
+ )
+ )
+ )
+ )
+ );
+ }
+
+ render() {
+ const {
+ dispatch,
+ selectedPage,
+ selectedRuntimeId,
+ isScanningUsb,
+ } = this.props;
+
+ return dom.aside(
+ {
+ className: `sidebar ${this.props.className || ""}`,
+ },
+ dom.ul(
+ {},
+ Localized(
+ { id: "about-debugging-sidebar-setup", attrs: { name: true } },
+ SidebarFixedItem({
+ dispatch,
+ icon: CONNECT_ICON,
+ isSelected: PAGE_TYPES.CONNECT === selectedPage,
+ key: PAGE_TYPES.CONNECT,
+ name: "Setup",
+ to: "/setup",
+ })
+ ),
+ Localized(
+ { id: "about-debugging-sidebar-this-firefox", attrs: { name: true } },
+ SidebarFixedItem({
+ icon: FIREFOX_ICON,
+ isSelected:
+ PAGE_TYPES.RUNTIME === selectedPage &&
+ selectedRuntimeId === RUNTIMES.THIS_FIREFOX,
+ key: RUNTIMES.THIS_FIREFOX,
+ name: "This Firefox",
+ to: `/runtime/${RUNTIMES.THIS_FIREFOX}`,
+ })
+ ),
+ SidebarItem(
+ {
+ className: "sidebar__adb-status",
+ },
+ dom.hr({ className: "separator separator--breathe" }),
+ this.renderAdbStatus()
+ ),
+ this.renderDevices(),
+ SidebarItem(
+ {
+ className: "sidebar-item--breathe sidebar__refresh-usb",
+ key: "refresh-devices",
+ },
+ RefreshDevicesButton({
+ dispatch,
+ isScanning: isScanningUsb,
+ })
+ )
+ ),
+ this.renderFooter()
+ );
+ }
+}
+
+module.exports = Sidebar;
diff --git a/devtools/client/aboutdebugging/src/components/sidebar/SidebarFixedItem.css b/devtools/client/aboutdebugging/src/components/sidebar/SidebarFixedItem.css
new file mode 100644
index 0000000000..7345b8e80f
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/components/sidebar/SidebarFixedItem.css
@@ -0,0 +1,29 @@
+/* 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/. */
+
+/*
+ * Layout of a fixed sidebar item
+ *
+ * +--------+----------------+
+ * | Icon | Name |
+ * +--------+----------------+
+ */
+
+.sidebar-fixed-item__container {
+ align-items: center;
+ border-radius: 2px;
+ display: grid;
+ grid-template-columns: 34px 1fr;
+ height: 100%;
+ font-size: var(--body-20-font-size);
+ font-weight: var(--body-20-font-weight);
+}
+
+.sidebar-fixed-item__icon {
+ fill: currentColor;
+ height: 24px;
+ margin-inline-end: 9px;
+ width: 24px;
+ -moz-context-properties: fill;
+}
diff --git a/devtools/client/aboutdebugging/src/components/sidebar/SidebarFixedItem.js b/devtools/client/aboutdebugging/src/components/sidebar/SidebarFixedItem.js
new file mode 100644
index 0000000000..e6ef008965
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/components/sidebar/SidebarFixedItem.js
@@ -0,0 +1,60 @@
+/* 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,
+ createFactory,
+} = 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 SidebarItem = createFactory(
+ require("devtools/client/aboutdebugging/src/components/sidebar/SidebarItem")
+);
+
+/**
+ * This component displays a fixed item in the Sidebar component.
+ */
+class SidebarFixedItem extends PureComponent {
+ static get propTypes() {
+ return {
+ icon: PropTypes.string.isRequired,
+ isSelected: PropTypes.bool.isRequired,
+ name: PropTypes.string.isRequired,
+ to: PropTypes.string,
+ };
+ }
+
+ render() {
+ const { icon, isSelected, name, to } = this.props;
+
+ return SidebarItem(
+ {
+ className: "sidebar-item--tall",
+ isSelected,
+ to,
+ },
+ dom.div(
+ {
+ className: "sidebar-fixed-item__container",
+ },
+ dom.img({
+ className: "sidebar-fixed-item__icon",
+ src: icon,
+ }),
+ dom.span(
+ {
+ className: "ellipsis-text",
+ title: name,
+ },
+ name
+ )
+ )
+ );
+ }
+}
+
+module.exports = SidebarFixedItem;
diff --git a/devtools/client/aboutdebugging/src/components/sidebar/SidebarItem.css b/devtools/client/aboutdebugging/src/components/sidebar/SidebarItem.css
new file mode 100644
index 0000000000..9727211f67
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/components/sidebar/SidebarItem.css
@@ -0,0 +1,53 @@
+/* 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/. */
+
+.sidebar-item {
+ --sidebar-text-color: var(--category-text);
+ --sidebar-selected-color: var(--category-text-selected);
+ --sidebar-background-hover: var(--category-background-hover);
+}
+
+.sidebar-item {
+ color: var(--sidebar-text-color);
+ border-radius: 2px;
+ padding-inline-end: var(--category-padding);
+ padding-inline-start: var(--category-padding);
+ transition: background-color var(--category-transition-duration);
+ user-select: none;
+}
+
+.sidebar-item--tall {
+ height: var(--category-height);
+}
+
+.sidebar-item--condensed {
+ height: calc(var(--base-unit) * 9);
+}
+
+.sidebar-item__link {
+ display: block;
+ height: 100%;
+}
+
+.sidebar-item__link,
+.sidebar-item__link:hover {
+ color: inherit; /* do not apply usual link colors, but grab this element parent's */
+}
+
+.sidebar-item:not(.sidebar-item--selectable) {
+ color: var(--grey-50);
+}
+
+.sidebar-item--selectable:hover {
+ background-color: var(--sidebar-background-hover);
+}
+
+.sidebar-item--selected {
+ color: var(--sidebar-selected-color);
+}
+
+.sidebar-item--breathe {
+ margin-block-start: calc(6 * var(--base-unit));
+ margin-block-end: calc(2 * var(--base-unit));
+}
diff --git a/devtools/client/aboutdebugging/src/components/sidebar/SidebarItem.js b/devtools/client/aboutdebugging/src/components/sidebar/SidebarItem.js
new file mode 100644
index 0000000000..9949ac82ec
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/components/sidebar/SidebarItem.js
@@ -0,0 +1,81 @@
+/* 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 Link = createFactory(
+ require("devtools/client/shared/vendor/react-router-dom").Link
+);
+
+/**
+ * This component is used as a wrapper by items in the sidebar.
+ */
+class SidebarItem extends PureComponent {
+ static get propTypes() {
+ return {
+ children: PropTypes.node.isRequired,
+ className: PropTypes.string,
+ isSelected: PropTypes.bool.isRequired,
+ to: PropTypes.string,
+ };
+ }
+
+ static get defaultProps() {
+ return {
+ isSelected: false,
+ };
+ }
+
+ renderContent() {
+ const { children, to } = this.props;
+
+ if (to) {
+ const isExternalUrl = /^http/.test(to);
+
+ return isExternalUrl
+ ? dom.a(
+ {
+ className: "sidebar-item__link",
+ href: to,
+ target: "_blank",
+ },
+ children
+ )
+ : Link(
+ {
+ className: "sidebar-item__link qa-sidebar-link",
+ to,
+ },
+ children
+ );
+ }
+
+ return children;
+ }
+
+ render() {
+ const { className, isSelected, to } = this.props;
+
+ return dom.li(
+ {
+ className:
+ "sidebar-item qa-sidebar-item" +
+ (className ? ` ${className}` : "") +
+ (isSelected
+ ? " sidebar-item--selected qa-sidebar-item-selected"
+ : "") +
+ (to ? " sidebar-item--selectable" : ""),
+ },
+ this.renderContent()
+ );
+ }
+}
+
+module.exports = SidebarItem;
diff --git a/devtools/client/aboutdebugging/src/components/sidebar/SidebarRuntimeItem.css b/devtools/client/aboutdebugging/src/components/sidebar/SidebarRuntimeItem.css
new file mode 100644
index 0000000000..423723a27f
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/components/sidebar/SidebarRuntimeItem.css
@@ -0,0 +1,41 @@
+/* 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/. */
+
+/*
+ * Layout of a runtime sidebar item
+ *
+ * +--------+----------------+---------------------------+
+ * | Icon | Runtime name | Connect button |
+ * +--------+----------------+---------------------------+
+ */
+
+.sidebar-runtime-item__container {
+ box-sizing: border-box;
+ height: var(--category-height);
+ align-items: center;
+ display: grid;
+ grid-column-gap: var(--base-unit);
+ grid-template-columns: calc(var(--base-unit) * 6) 1fr auto;
+ font-size: var(--body-20-font-size);
+ font-weight: var(--body-20-font-weight);
+}
+
+.sidebar-runtime-item__icon {
+ fill: currentColor;
+ -moz-context-properties: fill;
+}
+
+.sidebar-runtime-item__runtime {
+ line-height: 1;
+}
+
+.sidebar-runtime-item__runtime__details {
+ font-size: var(--caption-10-font-size);
+ font-weight: var(--caption-10-font-weight);
+ line-height: 1.2;
+}
+
+.sidebar-runtime-item__message:first-of-type {
+ margin-block-start: calc(var(--base-unit) * -1);
+}
diff --git a/devtools/client/aboutdebugging/src/components/sidebar/SidebarRuntimeItem.js b/devtools/client/aboutdebugging/src/components/sidebar/SidebarRuntimeItem.js
new file mode 100644
index 0000000000..ae22e97b46
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/components/sidebar/SidebarRuntimeItem.js
@@ -0,0 +1,221 @@
+/* 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 FluentReact = require("devtools/client/shared/vendor/fluent-react");
+const Localized = createFactory(FluentReact.Localized);
+
+const Message = createFactory(
+ require("devtools/client/aboutdebugging/src/components/shared/Message")
+);
+const SidebarItem = createFactory(
+ require("devtools/client/aboutdebugging/src/components/sidebar/SidebarItem")
+);
+const Actions = require("devtools/client/aboutdebugging/src/actions/index");
+const {
+ MESSAGE_LEVEL,
+} = require("devtools/client/aboutdebugging/src/constants");
+
+/**
+ * This component displays a runtime item of the Sidebar component.
+ */
+class SidebarRuntimeItem extends PureComponent {
+ static get propTypes() {
+ return {
+ deviceName: PropTypes.string,
+ dispatch: PropTypes.func.isRequired,
+ // Provided by wrapping the component with FluentReact.withLocalization.
+ getString: PropTypes.func.isRequired,
+ icon: PropTypes.string.isRequired,
+ isConnected: PropTypes.bool.isRequired,
+ isConnecting: PropTypes.bool.isRequired,
+ isConnectionFailed: PropTypes.bool.isRequired,
+ isConnectionNotResponding: PropTypes.bool.isRequired,
+ isConnectionTimeout: PropTypes.bool.isRequired,
+ isSelected: PropTypes.bool.isRequired,
+ isUnavailable: PropTypes.bool.isRequired,
+ isUnplugged: PropTypes.bool.isRequired,
+ name: PropTypes.string.isRequired,
+ runtimeId: PropTypes.string.isRequired,
+ };
+ }
+
+ renderConnectButton() {
+ const { isConnecting } = this.props;
+ const localizationId = isConnecting
+ ? "about-debugging-sidebar-item-connect-button-connecting"
+ : "about-debugging-sidebar-item-connect-button";
+ return Localized(
+ {
+ id: localizationId,
+ },
+ dom.button(
+ {
+ className: "default-button default-button--micro qa-connect-button",
+ disabled: isConnecting,
+ onClick: () => {
+ const { dispatch, runtimeId } = this.props;
+ dispatch(Actions.connectRuntime(runtimeId));
+ },
+ },
+ localizationId
+ )
+ );
+ }
+
+ renderMessage(flag, level, localizationId, className) {
+ if (!flag) {
+ return null;
+ }
+
+ return Message(
+ {
+ level,
+ className: `${className} sidebar-runtime-item__message`,
+ isCloseable: true,
+ },
+ Localized(
+ {
+ id: localizationId,
+ },
+ dom.p({ className: "word-wrap-anywhere" }, localizationId)
+ )
+ );
+ }
+
+ renderName() {
+ const {
+ deviceName,
+ getString,
+ isUnavailable,
+ isUnplugged,
+ name,
+ } = this.props;
+
+ let displayName, qaClassName;
+ if (isUnplugged) {
+ displayName = getString("about-debugging-sidebar-runtime-item-unplugged");
+ qaClassName = "qa-runtime-item-unplugged";
+ } else if (isUnavailable) {
+ displayName = getString(
+ "about-debugging-sidebar-runtime-item-waiting-for-browser"
+ );
+ qaClassName = "qa-runtime-item-waiting-for-browser";
+ } else {
+ displayName = name;
+ qaClassName = "qa-runtime-item-standard";
+ }
+
+ const localizationId = deviceName
+ ? "about-debugging-sidebar-runtime-item-name"
+ : "about-debugging-sidebar-runtime-item-name-no-device";
+
+ const className = "ellipsis-text sidebar-runtime-item__runtime";
+
+ function renderWithDevice() {
+ return dom.span(
+ {
+ className,
+ title: localizationId,
+ },
+ deviceName,
+ dom.br({}),
+ dom.span(
+ {
+ className: `sidebar-runtime-item__runtime__details ${qaClassName}`,
+ },
+ displayName
+ )
+ );
+ }
+
+ function renderNoDevice() {
+ return dom.span(
+ {
+ className,
+ title: localizationId,
+ },
+ displayName
+ );
+ }
+
+ return Localized(
+ {
+ id: localizationId,
+ attrs: { title: true },
+ $deviceName: deviceName,
+ $displayName: displayName,
+ },
+ deviceName ? renderWithDevice() : renderNoDevice()
+ );
+ }
+
+ render() {
+ const {
+ getString,
+ icon,
+ isConnected,
+ isConnectionFailed,
+ isConnectionTimeout,
+ isConnectionNotResponding,
+ isSelected,
+ isUnavailable,
+ runtimeId,
+ } = this.props;
+
+ const connectionStatus = isConnected
+ ? getString("aboutdebugging-sidebar-runtime-connection-status-connected")
+ : getString(
+ "aboutdebugging-sidebar-runtime-connection-status-disconnected"
+ );
+
+ return SidebarItem(
+ {
+ isSelected,
+ to: isConnected ? `/runtime/${encodeURIComponent(runtimeId)}` : null,
+ },
+ dom.section(
+ {
+ className: "sidebar-runtime-item__container",
+ },
+ dom.img({
+ className: "sidebar-runtime-item__icon ",
+ src: icon,
+ alt: connectionStatus,
+ title: connectionStatus,
+ }),
+ this.renderName(),
+ !isUnavailable && !isConnected ? this.renderConnectButton() : null
+ ),
+ this.renderMessage(
+ isConnectionFailed,
+ MESSAGE_LEVEL.ERROR,
+ "about-debugging-sidebar-item-connect-button-connection-failed",
+ "qa-connection-error"
+ ),
+ this.renderMessage(
+ isConnectionTimeout,
+ MESSAGE_LEVEL.ERROR,
+ "about-debugging-sidebar-item-connect-button-connection-timeout",
+ "qa-connection-timeout"
+ ),
+ this.renderMessage(
+ isConnectionNotResponding,
+ MESSAGE_LEVEL.WARNING,
+ "about-debugging-sidebar-item-connect-button-connection-not-responding",
+ "qa-connection-not-responding"
+ )
+ );
+ }
+}
+
+module.exports = FluentReact.withLocalization(SidebarRuntimeItem);
diff --git a/devtools/client/aboutdebugging/src/components/sidebar/moz.build b/devtools/client/aboutdebugging/src/components/sidebar/moz.build
new file mode 100644
index 0000000000..081ea2a848
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/components/sidebar/moz.build
@@ -0,0 +1,11 @@
+# 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(
+ "RefreshDevicesButton.js",
+ "Sidebar.js",
+ "SidebarFixedItem.js",
+ "SidebarItem.js",
+ "SidebarRuntimeItem.js",
+)