Bug 1444301 - Move dock functions to a new meatball menu; r?jryans draft
authorBrian Birtles <birtles@gmail.com>
Thu, 05 Apr 2018 10:13:21 +0900
changeset 778568 518dee7641441dcad0a1f46e9f0b0b894defb82c
parent 778369 f89a01b063dce8f817b8f36dcc21cdaba3ab7d9b
child 778569 96b60ce814a9eaff3640b5ca934d7902bd69808f
push id105521
push userbbirtles@mozilla.com
push dateFri, 06 Apr 2018 14:07:54 +0000
reviewersjryans
bugs1444301
milestone61.0a1
Bug 1444301 - Move dock functions to a new meatball menu; r?jryans MozReview-Commit-ID: IfFsiZnmw74
devtools/client/framework/components/toolbox-controller.js
devtools/client/framework/components/toolbox-toolbar.js
devtools/client/framework/toolbox.js
devtools/client/jar.mn
devtools/client/locales/en-US/toolbox.properties
devtools/client/themes/images/dock-bottom.svg
devtools/client/themes/images/dock-side.svg
devtools/client/themes/images/dock-undock.svg
devtools/client/themes/images/more.svg
devtools/client/themes/toolbox.css
devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_nodes_highlight.js
devtools/client/webconsole/test/head.js
--- a/devtools/client/framework/components/toolbox-controller.js
+++ b/devtools/client/framework/components/toolbox-controller.js
@@ -21,33 +21,33 @@ class ToolboxController extends Componen
     // state, and for the definitions of the props that are expected to be passed in.
     this.state = {
       focusedButton: ELEMENT_PICKER_ID,
       toolboxButtons: [],
       currentToolId: null,
       highlightedTools: new Set(),
       panelDefinitions: [],
       hostTypes: [],
-      areDockButtonsEnabled: true,
+      areDockOptionsEnabled: true,
       canCloseToolbox: true,
       canRender: false,
       buttonIds: [],
       checkedButtonsUpdated: () => {
         this.forceUpdate();
       }
     };
 
     this.setFocusedButton = this.setFocusedButton.bind(this);
     this.setToolboxButtons = this.setToolboxButtons.bind(this);
     this.setCurrentToolId = this.setCurrentToolId.bind(this);
     this.highlightTool = this.highlightTool.bind(this);
     this.unhighlightTool = this.unhighlightTool.bind(this);
     this.setOptionsPanel = this.setOptionsPanel.bind(this);
     this.setHostTypes = this.setHostTypes.bind(this);
-    this.setDockButtonsEnabled = this.setDockButtonsEnabled.bind(this);
+    this.setDockOptionsEnabled = this.setDockOptionsEnabled.bind(this);
     this.setCanCloseToolbox = this.setCanCloseToolbox.bind(this);
     this.setCanRender = this.setCanRender.bind(this);
     this.setPanelDefinitions = this.setPanelDefinitions.bind(this);
     this.updateButtonIds = this.updateButtonIds.bind(this);
     this.updateFocusedButton = this.updateFocusedButton.bind(this);
   }
 
   shouldComponentUpdate() {
@@ -64,28 +64,26 @@ class ToolboxController extends Componen
    * The button and tab ids must be known in order to be able to focus left and right
    * using the arrow keys.
    */
   updateButtonIds() {
     const {
       toolboxButtons,
       panelDefinitions,
       optionsPanel,
-      hostTypes,
       canCloseToolbox,
     } = this.state;
 
     // This is a little gnarly, but go through all of the state and extract the IDs.
     this.setState({
       buttonIds: [
         ...toolboxButtons.filter(btn => btn.isInStartContainer).map(({id}) => id),
         ...panelDefinitions.map(({id}) => id),
         ...toolboxButtons.filter(btn => !btn.isInStartContainer).map(({id}) => id),
         optionsPanel ? optionsPanel.id : null,
-        ...hostTypes.map(({position}) => "toolbox-dock-" + position),
         canCloseToolbox ? "toolbox-close" : null
       ].filter(id => id)
     });
 
     this.updateFocusedButton();
   }
 
   updateFocusedButton() {
@@ -129,22 +127,22 @@ class ToolboxController extends Componen
   unhighlightTool(id) {
     let { highlightedTools } = this.state;
     if (highlightedTools.has(id)) {
       highlightedTools.delete(id);
       this.setState({ highlightedTools });
     }
   }
 
-  setDockButtonsEnabled(areDockButtonsEnabled) {
-    this.setState({ areDockButtonsEnabled }, this.updateButtonIds);
+  setDockOptionsEnabled(areDockOptionsEnabled) {
+    this.setState({ areDockOptionsEnabled });
   }
 
   setHostTypes(hostTypes) {
-    this.setState({ hostTypes }, this.updateButtonIds);
+    this.setState({ hostTypes });
   }
 
   setCanCloseToolbox(canCloseToolbox) {
     this.setState({ canCloseToolbox }, this.updateButtonIds);
   }
 
   setPanelDefinitions(panelDefinitions) {
     this.setState({ panelDefinitions }, this.updateButtonIds);
--- a/devtools/client/framework/components/toolbox-toolbar.js
+++ b/devtools/client/framework/components/toolbox-toolbar.js
@@ -3,16 +3,18 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const { Component, 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 {div, button} = dom;
 
+const Menu = require("devtools/client/framework/menu");
+const MenuItem = require("devtools/client/framework/menu-item");
 const ToolboxTab = createFactory(require("devtools/client/framework/components/toolbox-tab"));
 const ToolboxTabs = createFactory(require("devtools/client/framework/components/toolbox-tabs"));
 
 /**
  * This is the overall component for the toolbox toolbar. It is designed to not know how
  * the state is being managed, and attempts to be as pure as possible. The
  * ToolboxController component controls the changing state, and passes in everything as
  * props.
@@ -70,17 +72,17 @@ class ToolboxToolbar extends Component {
       ? (
         div(
           containerProps,
           renderToolboxButtonsStart(this.props),
           ToolboxTabs(this.props),
           renderToolboxButtonsEnd(this.props),
           renderOptions(this.props),
           renderSeparator(),
-          renderDockButtons(this.props)
+          renderToolboxControls(this.props)
         )
       )
       : div(containerProps);
   }
 }
 
 module.exports = ToolboxToolbar;
 
@@ -188,69 +190,65 @@ function renderOptions({focusedButton, c
 /**
  * Render a separator.
  */
 function renderSeparator() {
   return div({className: "devtools-separator"});
 }
 
 /**
- * Render the dock buttons, and handle all the cases for what type of host the toolbox
- * is attached to. The following props are expected.
+ * Render the toolbox control buttons. The following props are expected:
  *
  * @param {string} focusedButton
  *        The id of the focused button.
  * @param {Object[]} hostTypes
  *        Array of host type objects.
  * @param {string} hostTypes[].position
  *        Position name.
  * @param {Function} hostTypes[].switchHost
  *        Function to switch the host.
- * @param {boolean} areDockButtonsEnabled
+ * @param {boolean} areDockOptionsEnabled
  *        They are not enabled in certain situations like when they are in the
  *        WebIDE.
  * @param {boolean} canCloseToolbox
  *        Do we need to add UI for closing the toolbox? We don't when the
  *        toolbox is undocked, for example.
  * @param {Function} closeToolbox
  *        Completely close the toolbox.
  * @param {Function} focusButton
  *        Keep a record of the currently focused button.
  * @param {Object} L10N
  *        Localization interface.
  */
-function renderDockButtons(props) {
+function renderToolboxControls(props) {
   const {
     focusedButton,
     closeToolbox,
     hostTypes,
     focusButton,
     L10N,
-    areDockButtonsEnabled,
+    areDockOptionsEnabled,
     canCloseToolbox,
   } = props;
 
-  let buttons = [];
+  const meatballMenuButtonId = "toolbox-meatball-menu-button";
 
-  if (areDockButtonsEnabled) {
-    hostTypes.forEach(hostType => {
-      const id = "toolbox-dock-" + hostType.position;
-      buttons.push(button({
-        id,
-        onFocus: () => focusButton(id),
-        className: "toolbox-dock-button devtools-button",
-        title: L10N.getStr(`toolboxDockButtons.${hostType.position}.tooltip`),
-        onClick: e => {
-          hostType.switchHost();
-          focusButton(id);
-        },
-        tabIndex: focusedButton === id ? "0" : "-1",
-      }));
-    });
-  }
+  const meatballMenuButton = button({
+    id: meatballMenuButtonId,
+    onFocus: () => focusButton(meatballMenuButtonId),
+    className: "devtools-button",
+    title: L10N.getStr("toolbox.meatballMenu.button.tooltip"),
+    onClick: evt => {
+      showMeatballMenu(evt.target, {
+        ...props,
+        hostTypes: areDockOptionsEnabled ? hostTypes : [],
+      });
+    },
+    tabIndex: focusedButton === meatballMenuButtonId ? "0" : "-1",
+  });
 
   const closeButtonId = "toolbox-close";
 
   const closeButton = canCloseToolbox
     ? button({
       id: closeButtonId,
       onFocus: () => focusButton(closeButtonId),
       className: "devtools-button",
@@ -258,12 +256,58 @@ function renderDockButtons(props) {
       onClick: () => {
         closeToolbox();
       },
       tabIndex: focusedButton === "toolbox-close" ? "0" : "-1",
     })
     : null;
 
   return div({id: "toolbox-controls"},
-    div({id: "toolbox-dock-buttons"}, ...buttons),
+    meatballMenuButton,
     closeButton
   );
 }
+
+/**
+ * Display the "..." menu (affectionately known as the meatball menu).
+ *
+ * @param {Object} menuButton
+ *        The <button> element from which the menu should pop out. The geometry
+ *        of this element is used to position the menu.
+ * @param {Object} props
+ *        Properties as described below.
+ * @param {Object[]} props.hostTypes
+ *        Array of host type objects.
+ * @param {string} props.hostTypes[].position
+ *        Position name.
+ * @param {Function} props.hostTypes[].switchHost
+ *        Function to switch the host.
+ *        This array will be empty if we shouldn't shouldn't show any dock
+ *        options.
+ * @param {Object} props.L10N
+ *        Localization interface.
+ * @param {Object} props.toolbox
+ *        The devtools toolbox. Used by the Menu component to determine which
+ *        document to use.
+ */
+function showMeatballMenu(menuButton, {hostTypes, L10N, toolbox}) {
+  const menu = new Menu({ id: "toolbox-meatball-menu" });
+
+  for (const hostType of hostTypes) {
+    menu.append(new MenuItem({
+      id: `toolbox-meatball-menu-dock-${hostType.position}`,
+      label: L10N.getStr(
+        `toolbox.meatballMenu.dock.${hostType.position}.label`
+      ),
+      click: () => hostType.switchHost(),
+    }));
+  }
+
+  // (Yes, it's true we might end up with an empty menu here. Don't worry,
+  // by the end of this patch series that won't be the case.)
+
+  const rect = menuButton.getBoundingClientRect();
+  const screenX = menuButton.ownerDocument.defaultView.mozInnerScreenX;
+  const screenY = menuButton.ownerDocument.defaultView.mozInnerScreenY;
+
+  // Display the popup below the button.
+  menu.popup(rect.left + screenX, rect.bottom + screenY, toolbox);
+}
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -482,17 +482,17 @@ Toolbox.prototype = {
 
       this.shortcuts = new KeyShortcuts({
         window: this.doc.defaultView
       });
       // Get the DOM element to mount the ToolboxController to.
       this._componentMount = this.doc.getElementById("toolbox-toolbar-mount");
 
       this._mountReactComponent();
-      this._buildDockButtons();
+      this._buildDockOptions();
       this._buildOptions();
       this._buildTabs();
       this._applyCacheSettings();
       this._applyServiceWorkersTestingSettings();
       this._addKeysToWindow();
       this._addReloadKeys();
       this._addHostListeners();
       this._registerOverlays();
@@ -1043,26 +1043,26 @@ Toolbox.prototype = {
       this._notificationBox = Object.assign(
         this.ReactDOM.render(NotificationBox({}), box),
         PriorityLevels);
     }
     return this._notificationBox;
   },
 
   /**
-   * Build the buttons for changing hosts. Called every time
+   * Build the options for changing hosts. Called every time
    * the host changes.
    */
-  _buildDockButtons: function() {
+  _buildDockOptions: function() {
     if (!this._target.isLocalTab) {
-      this.component.setDockButtonsEnabled(false);
+      this.component.setDockOptionsEnabled(false);
       return;
     }
 
-    this.component.setDockButtonsEnabled(true);
+    this.component.setDockOptionsEnabled(true);
     this.component.setCanCloseToolbox(this.hostType !== Toolbox.HostType.WINDOW);
 
     let sideEnabled = Services.prefs.getBoolPref(this._prefs.SIDE_ENABLED);
 
     let hostTypes = [];
     for (let type in Toolbox.HostType) {
       let position = Toolbox.HostType[type];
       if (position == this.hostType ||
@@ -2349,17 +2349,17 @@ Toolbox.prototype = {
     });
 
     return this.once("host-changed");
   },
 
   _onSwitchedHost: function({ hostType }) {
     this._hostType = hostType;
 
-    this._buildDockButtons();
+    this._buildDockOptions();
     this._addKeysToWindow();
 
     // We blurred the tools at start of switchHost, but also when clicking on
     // host switching button. We now have to restore the focus.
     this.focusTool(this.currentToolId, true);
 
     this.emit("host-changed");
     this._telemetry.log(HOST_HISTOGRAM, this._getTelemetryHostId());
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -181,31 +181,29 @@ devtools.jar:
     skin/images/item-toggle.svg (themes/images/item-toggle.svg)
     skin/images/item-arrow-dark-rtl.svg (themes/images/item-arrow-dark-rtl.svg)
     skin/images/item-arrow-dark-ltr.svg (themes/images/item-arrow-dark-ltr.svg)
     skin/images/item-arrow-rtl.svg (themes/images/item-arrow-rtl.svg)
     skin/images/item-arrow-ltr.svg (themes/images/item-arrow-ltr.svg)
     skin/images/dropmarker.svg (themes/images/dropmarker.svg)
     skin/boxmodel.css (themes/boxmodel.css)
     skin/images/geometry-editor.svg (themes/images/geometry-editor.svg)
+    skin/images/more.svg (themes/images/more.svg)
     skin/images/pause.svg (themes/images/pause.svg)
     skin/images/play.svg (themes/images/play.svg)
     skin/images/rewind.svg (themes/images/rewind.svg)
     skin/images/debugger-step-in.svg (themes/images/debugger-step-in.svg)
     skin/images/debugger-step-out.svg (themes/images/debugger-step-out.svg)
     skin/images/debugger-step-over.svg (themes/images/debugger-step-over.svg)
     skin/images/debugger-toggleBreakpoints.svg (themes/images/debugger-toggleBreakpoints.svg)
     skin/images/jump-definition.svg (themes/images/jump-definition.svg)
     skin/images/tracer-icon.png (themes/images/tracer-icon.png)
     skin/images/tracer-icon@2x.png (themes/images/tracer-icon@2x.png)
     skin/images/toggle-tools.png (themes/images/toggle-tools.png)
     skin/images/toggle-tools@2x.png (themes/images/toggle-tools@2x.png)
-    skin/images/dock-bottom.svg (themes/images/dock-bottom.svg)
-    skin/images/dock-side.svg (themes/images/dock-side.svg)
-    skin/images/dock-undock.svg (themes/images/dock-undock.svg)
     skin/floating-scrollbars-dark-theme.css (themes/floating-scrollbars-dark-theme.css)
     skin/floating-scrollbars-responsive-design.css (themes/floating-scrollbars-responsive-design.css)
     skin/inspector.css (themes/inspector.css)
     skin/images/profiler-stopwatch.svg (themes/images/profiler-stopwatch.svg)
     skin/images/debugging-addons.svg (themes/images/debugging-addons.svg)
     skin/images/debugging-tabs.svg (themes/images/debugging-tabs.svg)
     skin/images/debugging-workers.svg (themes/images/debugging-workers.svg)
     skin/images/gcli_sec_bad.svg (themes/images/gcli_sec_bad.svg)
@@ -305,9 +303,9 @@ devtools.jar:
     content/netmonitor/index.html (netmonitor/index.html)
     content/netmonitor/initializer.js (netmonitor/initializer.js)
 
     # Devtools-components
     skin/images/devtools-components/arrow.svg (themes/images/devtools-components/arrow.svg)
 
     # Devtools-reps
     skin/images/devtools-reps/jump-definition.svg (themes/images/devtools-reps/jump-definition.svg)
-    skin/images/devtools-reps/open-inspector.svg (themes/images/devtools-reps/open-inspector.svg)
\ No newline at end of file
+    skin/images/devtools-reps/open-inspector.svg (themes/images/devtools-reps/open-inspector.svg)
--- a/devtools/client/locales/en-US/toolbox.properties
+++ b/devtools/client/locales/en-US/toolbox.properties
@@ -1,16 +1,12 @@
 # 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/.
 
-toolboxDockButtons.bottom.tooltip=Dock to bottom of browser window
-toolboxDockButtons.side.tooltip=Dock to side of browser window
-toolboxDockButtons.window.tooltip=Show in separate window
-
 # LOCALIZATION NOTE (toolboxToggleButton.errors): Semi-colon list of plural
 # forms.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 # #1 number of errors in the current web page
 toolboxToggleButton.errors=#1 error;#1 errors
 
 # LOCALIZATION NOTE (toolboxToggleButton.warnings): Semi-colon list of plural
 # forms.
@@ -151,16 +147,27 @@ toolbox.frames.tooltip=Select an iframe 
 toolbox.showFrames.key=Alt+Down
 
 # LOCALIZATION NOTE (toolbox.noautohide.tooltip): This is the label for
 # the button to force the popups/panels to stay visible on blur.
 # This is only visible in the browser toolbox as it is meant for
 # addon developers and Firefox contributors.
 toolbox.noautohide.tooltip=Disable popup auto hide
 
+# LOCALIZATION NOTE (toolbox.meatballMenu.button.tooltip): This is the tooltip
+# for the "..." button on the developer tools toolbox.
+toolbox.meatballMenu.button.tooltip=Customize Developer Tools and get help
+
+# LOCALIZATION NOTE (toolbox.meatballMenu.dock.*.label): These labels are shown
+# in the "..." menu in the toolbox and represent the different arrangements for
+# docking (or undocking) the developer tools toolbox.
+toolbox.meatballMenu.dock.bottom.label=Dock to bottom
+toolbox.meatballMenu.dock.side.label=Dock to side
+toolbox.meatballMenu.dock.window.label=Undock
+
 # LOCALIZATION NOTE (toolbox.closebutton.tooltip): This is the tooltip for
 # the close button the developer tools toolbox.
 toolbox.closebutton.tooltip=Close Developer Tools
 
 # LOCALIZATION NOTE (toolbox.allToolsButton.tooltip): This is the tooltip for the
 # "all tools" button displayed when some tools are hidden by overflow of the toolbar.
 toolbox.allToolsButton.tooltip=Select another tool
 
deleted file mode 100644
--- a/devtools/client/themes/images/dock-bottom.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="context-fill #0b0b0b">
-  <path d="M10.004 3H.996C.999 3 1 3 1 3.002v9.996c0-.001.003.002-.004.002h9.008c-.003 0-.004 0-.004-.002V3.002c0 .001-.003-.002.004-.002zm0-1c.55 0 .996.456.996 1.002v9.996A.998.998 0 0 1 10.004 14H.996C.446 14 0 13.544 0 12.998V3.002A.998.998 0 0 1 .996 2h9.008zm-.41 8H.996v1h9.01v-1h-.41z"/>
-</svg>
deleted file mode 100644
--- a/devtools/client/themes/images/dock-side.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="context-fill #0b0b0b">
-  <path d="M1 2.996v9.008c0-.003 0-.004.002-.004h9.996c-.001 0 .002-.003.002.004V2.996c0 .003 0 .004-.002.004H1.002C1.003 3 1 3.003 1 2.996zm-1 0C0 2.446.456 2 1.002 2h9.996A.998.998 0 0 1 12 2.996v9.008c0 .55-.456.996-1.002.996H1.002A.998.998 0 0 1 0 12.004V2.996zm8 .413V12h1V3H8v.41z"/>
-</svg>
deleted file mode 100644
--- a/devtools/client/themes/images/dock-undock.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="context-fill #0b0b0b">
-  <path d="M13.003 1.941H6.997c.008 0 .003.004.003.008v6.102c0 .004.004.008-.003.008h6.006c-.008 0-.003-.004-.003-.008V1.949c0-.004-.004-.008.003-.008zm0-.941c.55 0 .997.43.997.95v6.1c0 .525-.453.95-.997.95H6.997C6.447 9 6 8.57 6 8.05v-6.1c0-.525.453-.95.997-.95h6.006z"/>
-  <path d="M9 9.91v-.278h1v1.183c0 .516-.453.935-.997.935H2.997c-.55 0-.997-.43-.997-.95V4.7c0-.525.444-.95 1.006-.95h2.288v.941H3.006C3 4.691 3 4.691 3 4.7v6.102c0 .004.004.008-.003.008h6.006c-.004 0-.003-.001-.003.006v-.248-.657-.278h1v1.183c0 .516-.453.935-.997.935H2.997c-.55 0-.997-.43-.997-.95V4.7c0-.525.444-.95 1.006-.95h2.288v.941H3.006C3 4.691 3 4.691 3 4.7v6.102c0 .004.004.008-.003.008h6.006c-.004 0-.003-.001-.003.006v-.248-.657z"/>
-  <path d="M12.52 5H6.976v1h6.046V5zM6.5 7H2.975v1H7V7z"/>
-</svg>
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/more.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 xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <path fill="context-fill" d="M2 6a2 2 0 1 0 2 2 2 2 0 0 0-2-2zm6 0a2 2 0 1 0 2 2 2 2 0 0 0-2-2zm6 0a2 2 0 1 0 2 2 2 2 0 0 0-2-2z"></path>
+</svg>
--- a/devtools/client/themes/toolbox.css
+++ b/devtools/client/themes/toolbox.css
@@ -1,18 +1,16 @@
 /* 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/. */
 
 :root {
   --close-button-image: url(chrome://devtools/skin/images/close.svg);
-  --dock-bottom-image: url(chrome://devtools/skin/images/dock-bottom.svg);
-  --dock-side-image: url(chrome://devtools/skin/images/dock-side.svg);
-  --dock-undock-image: url(chrome://devtools/skin/images/dock-undock.svg);
+  --more-button-image: url(chrome://devtools/skin/images/more.svg);
 
   --command-paintflashing-image: url(images/command-paintflashing.svg);
   --command-screenshot-image: url(images/command-screenshot.svg);
   --command-responsive-image: url(images/command-responsivemode.svg);
   --command-scratchpad-image: url(images/tool-scratchpad.svg);
   --command-pick-image: url(images/command-pick.svg);
   --command-pick-accessibility-image: url(images/command-pick-accessibility.svg);
   --command-frames-image: url(images/command-frames.svg);
@@ -57,18 +55,17 @@
   overflow: hidden;
 }
 
 /* Set flex attribute to Toolbox buttons and Picker container so,
    they don't overlap with the tab bar */
 #toolbox-buttons-start,
 #toolbox-buttons-end,
 #toolbox-option-container,
-#toolbox-controls,
-#toolbox-dock-buttons {
+#toolbox-controls {
   display: flex;
   align-items: stretch;
 }
 
 /* Toolbox tabs */
 
 .devtools-tab {
   position: relative;
@@ -176,33 +173,24 @@
 
 /* Toolbox controls */
 
 
 #toolbox-close::before {
   background-image: var(--close-button-image);
 }
 
-#toolbox-dock-bottom::before {
-  background-image: var(--dock-bottom-image);
-}
-
-#toolbox-dock-side::before {
-  background-image: var(--dock-side-image);
-}
-
-#toolbox-dock-window::before {
-  background-image: var(--dock-undock-image);
+#toolbox-meatball-menu-button::before {
+  background-image: var(--more-button-image);
 }
 
 /* Command buttons */
 
 .command-button,
-#toolbox-controls > button,
-#toolbox-dock-buttons > button {
+#toolbox-controls > button {
   /* !important is needed to override .devtools-button rules in common.css */
   padding: 0 !important;
   margin: 0 !important;
   border: none !important;
   border-radius: 0 !important;
   position: relative;
   min-width: 24px;
 }
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_nodes_highlight.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_nodes_highlight.js
@@ -38,14 +38,14 @@ add_task(async function() {
   let onNodeHighlight = toolbox.once("node-highlight");
   EventUtils.synthesizeMouseAtCenter(node, {type: "mousemove"}, view);
 
   let nodeFront = await onNodeHighlight;
   is(nodeFront.displayName, "h1", "The correct node was highlighted");
 
   info("Unhighlight the node by moving away from the node");
   let onNodeUnhighlight = toolbox.once("node-unhighlight");
-  let btn = toolbox.doc.querySelector(".toolbox-dock-button");
+  let btn = toolbox.doc.getElementById("toolbox-meatball-menu-button");
   EventUtils.synthesizeMouseAtCenter(btn, {type: "mousemove"}, view);
 
   await onNodeUnhighlight;
   ok(true, "node-unhighlight event was fired when moving away from the node");
 });
--- a/devtools/client/webconsole/test/head.js
+++ b/devtools/client/webconsole/test/head.js
@@ -1682,17 +1682,18 @@ function checkDomElementHighlightingForI
            "Expected attribute's name is present");
         is(attrs[i].value, testData.attrs[i].value,
            "Expected attribute's value is present");
       }
     }
 
     info("Unhighlight the node by moving away from the markup view");
     let onNodeUnhighlight = toolbox.once("node-unhighlight");
-    let btn = inspector.toolbox.doc.querySelector(".toolbox-dock-button");
+    let btn =
+      inspector.toolbox.doc.getElementById("toolbox-meatball-menu-button");
     EventUtils.synthesizeMouseAtCenter(btn, {type: "mousemove"},
       inspector.toolbox.win);
     yield onNodeUnhighlight;
 
     info("Switching back to the console");
     yield toolbox.selectTool("webconsole");
   }