Bug 1449100 - Move network details panel toggle buton next to the sidebar tabs. r=Honza draft
authorGabriel Luong <gabriel.luong@gmail.com>
Mon, 09 Apr 2018 16:13:50 -0400
changeset 779409 88251bb05fccc2a211bf422c2031d1c0ae34ebe2
parent 779408 abb2fafe775b3e58cdff89164a229883755a08df
push id105763
push userbmo:gl@mozilla.com
push dateMon, 09 Apr 2018 20:28:31 +0000
reviewersHonza
bugs1449100
milestone61.0a1
Bug 1449100 - Move network details panel toggle buton next to the sidebar tabs. r=Honza MozReview-Commit-ID: JWxqKxjOeX8
devtools/client/locales/en-US/netmonitor.properties
devtools/client/netmonitor/src/assets/styles/Toolbar.css
devtools/client/netmonitor/src/assets/styles/netmonitor.css
devtools/client/netmonitor/src/components/NetworkDetailsPanel.js
devtools/client/netmonitor/src/components/TabboxPanel.js
devtools/client/netmonitor/src/components/Toolbar.js
devtools/client/netmonitor/src/selectors/ui.js
devtools/client/netmonitor/test/browser_net_brotli.js
devtools/client/netmonitor/test/browser_net_clear.js
devtools/client/netmonitor/test/browser_net_json-b64.js
devtools/client/netmonitor/test/browser_net_json-long.js
devtools/client/netmonitor/test/browser_net_json-malformed.js
devtools/client/netmonitor/test/browser_net_json-null.js
devtools/client/netmonitor/test/browser_net_json_custom_mime.js
devtools/client/netmonitor/test/browser_net_json_text_mime.js
devtools/client/netmonitor/test/browser_net_jsonp.js
devtools/client/netmonitor/test/browser_net_large-response.js
devtools/client/netmonitor/test/browser_net_pane-collapse.js
devtools/client/netmonitor/test/browser_net_pane-toggle.js
devtools/client/netmonitor/test/browser_net_post-data-03.js
devtools/client/netmonitor/test/browser_net_post-data-04.js
devtools/client/netmonitor/test/browser_net_prefs-reload.js
devtools/client/netmonitor/test/browser_net_security-details.js
devtools/client/netmonitor/test/browser_net_security-error.js
devtools/client/netmonitor/test/browser_net_simple-request-details.js
devtools/client/netmonitor/test/browser_net_simple-request.js
devtools/client/netmonitor/test/browser_net_sort-01.js
devtools/client/netmonitor/test/browser_net_sort-02.js
devtools/client/netmonitor/test/browser_net_streaming-response.js
--- a/devtools/client/locales/en-US/netmonitor.properties
+++ b/devtools/client/locales/en-US/netmonitor.properties
@@ -53,20 +53,16 @@ netmonitor.security.hostHeader=Host %S:
 # defined:
 #   Organization: <Not Available>
 netmonitor.security.notAvailable=<Not Available>
 
 # LOCALIZATION NOTE (collapseDetailsPane): This is the tooltip for the button
 # that collapses the network details pane in the UI.
 collapseDetailsPane=Hide request details
 
-# LOCALIZATION NOTE (expandDetailsPane): This is the tooltip for the button
-# that expands the network details pane in the UI.
-expandDetailsPane=Show request details
-
 # LOCALIZATION NOTE (headersEmptyText): This is the text displayed in the
 # headers tab of the network details pane when there are no headers available.
 headersEmptyText=No headers for this request
 
 # LOCALIZATION NOTE (headersFilterText): This is the text displayed in the
 # headers tab of the network details pane for the filtering input.
 headersFilterText=Filter headers
 
--- a/devtools/client/netmonitor/src/assets/styles/Toolbar.css
+++ b/devtools/client/netmonitor/src/assets/styles/Toolbar.css
@@ -40,32 +40,8 @@
   bottom: 1px;
 }
 
 .devtools-checkbox-label {
   margin-inline-start: 10px;
   margin-inline-end: 3px;
   white-space: nowrap;
 }
-
-/* Network details panel toggle */
-
-.network-details-panel-toggle:dir(ltr)::before,
-.network-details-panel-toggle.pane-collapsed:dir(rtl)::before {
-  background-image: var(--theme-pane-collapse-image);
-}
-
-.network-details-panel-toggle.pane-collapsed:dir(ltr)::before,
-.network-details-panel-toggle:dir(rtl)::before {
-  background-image: var(--theme-pane-expand-image);
-}
-
-/* Responsive web design support */
-
-@media (max-width: 700px) {
-  .network-details-panel-toggle:dir(ltr)::before {
-    transform: rotate(90deg);
-  }
-
-  .network-details-panel-toggle:dir(rtl)::before {
-    transform: rotate(-90deg);
-  }
-}
--- a/devtools/client/netmonitor/src/assets/styles/netmonitor.css
+++ b/devtools/client/netmonitor/src/assets/styles/netmonitor.css
@@ -1,12 +1,13 @@
 /* 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/. */
 
+@import "resource://devtools/client/shared/components/SidebarToggle.css";
 @import "resource://devtools/client/shared/components/splitter/SplitBox.css";
 @import "resource://devtools/client/shared/components/tree/TreeView.css";
 @import "resource://devtools/client/shared/components/tabs/Tabs.css";
 @import "resource://devtools/client/shared/components/tabs/TabBar.css";
 @import "chrome://devtools/skin/components-frame.css";
 @import "chrome://devtools/content/sourceeditor/codemirror/lib/codemirror.css";
 @import "chrome://devtools/content/sourceeditor/codemirror/addon/dialog/dialog.css";
 @import "chrome://devtools/content/sourceeditor/codemirror/mozilla.css";
--- a/devtools/client/netmonitor/src/components/NetworkDetailsPanel.js
+++ b/devtools/client/netmonitor/src/components/NetworkDetailsPanel.js
@@ -26,16 +26,17 @@ const { div } = dom;
  */
 function NetworkDetailsPanel({
   connector,
   activeTabId,
   cloneSelectedRequest,
   request,
   selectTab,
   sourceMapService,
+  toggleNetworkDetails,
   openLink,
 }) {
   if (!request) {
     return null;
   }
 
   return (
     div({ className: "network-details-panel" },
@@ -43,16 +44,17 @@ function NetworkDetailsPanel({
         TabboxPanel({
           activeTabId,
           cloneSelectedRequest,
           connector,
           openLink,
           request,
           selectTab,
           sourceMapService,
+          toggleNetworkDetails,
         }) :
         CustomRequestPanel({
           connector,
           request,
         })
     )
   );
 }
@@ -62,21 +64,23 @@ NetworkDetailsPanel.displayName = "Netwo
 NetworkDetailsPanel.propTypes = {
   connector: PropTypes.object.isRequired,
   activeTabId: PropTypes.string,
   cloneSelectedRequest: PropTypes.func.isRequired,
   open: PropTypes.bool,
   request: PropTypes.object,
   selectTab: PropTypes.func.isRequired,
   sourceMapService: PropTypes.object,
+  toggleNetworkDetails: PropTypes.func.isRequired,
   openLink: PropTypes.func,
 };
 
 module.exports = connect(
   (state) => ({
     activeTabId: state.ui.detailsPanelSelectedTab,
     request: getSelectedRequest(state),
   }),
   (dispatch) => ({
     cloneSelectedRequest: () => dispatch(Actions.cloneSelectedRequest()),
     selectTab: (tabId) => dispatch(Actions.selectDetailsPanelTab(tabId)),
+    toggleNetworkDetails: () => dispatch(Actions.toggleNetworkDetails()),
   }),
 )(NetworkDetailsPanel);
--- a/devtools/client/netmonitor/src/components/TabboxPanel.js
+++ b/devtools/client/netmonitor/src/components/TabboxPanel.js
@@ -15,16 +15,17 @@ const TabPanel = createFactory(require("
 const CookiesPanel = createFactory(require("./CookiesPanel"));
 const HeadersPanel = createFactory(require("./HeadersPanel"));
 const ParamsPanel = createFactory(require("./ParamsPanel"));
 const ResponsePanel = createFactory(require("./ResponsePanel"));
 const SecurityPanel = createFactory(require("./SecurityPanel"));
 const StackTracePanel = createFactory(require("./StackTracePanel"));
 const TimingsPanel = createFactory(require("./TimingsPanel"));
 
+const COLLAPSE_DETAILS_PANE = L10N.getStr("collapseDetailsPane");
 const COOKIES_TITLE = L10N.getStr("netmonitor.tab.cookies");
 const HEADERS_TITLE = L10N.getStr("netmonitor.tab.headers");
 const PARAMS_TITLE = L10N.getStr("netmonitor.tab.params");
 const RESPONSE_TITLE = L10N.getStr("netmonitor.tab.response");
 const SECURITY_TITLE = L10N.getStr("netmonitor.tab.security");
 const STACK_TRACE_TITLE = L10N.getStr("netmonitor.tab.stackTrace");
 const TIMINGS_TITLE = L10N.getStr("netmonitor.tab.timings");
 
@@ -35,28 +36,35 @@ const TIMINGS_TITLE = L10N.getStr("netmo
 function TabboxPanel({
   activeTabId,
   cloneSelectedRequest = () => {},
   connector,
   openLink,
   request,
   selectTab,
   sourceMapService,
+  toggleNetworkDetails,
 }) {
   if (!request) {
     return null;
   }
 
   return (
     Tabbar({
       activeTabId,
       menuDocument: window.parent.document,
       onSelect: selectTab,
       renderOnlySelected: true,
       showAllTabsMenu: true,
+      sidebarToggleButton: {
+        collapsed: false,
+        collapsePaneTitle: COLLAPSE_DETAILS_PANE,
+        expandPaneTitle: "",
+        onClick: toggleNetworkDetails,
+      },
     },
       TabPanel({
         id: PANELS.HEADERS,
         title: HEADERS_TITLE,
       },
         HeadersPanel({
           cloneSelectedRequest,
           connector,
--- a/devtools/client/netmonitor/src/components/Toolbar.js
+++ b/devtools/client/netmonitor/src/components/Toolbar.js
@@ -10,30 +10,27 @@ const dom = require("devtools/client/sha
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const { connect } = require("devtools/client/shared/redux/visibility-handler-connect");
 
 const Actions = require("../actions/index");
 const { FILTER_SEARCH_DELAY, FILTER_TAGS } = require("../constants");
 const {
   getRecordingState,
   getTypeFilteredRequests,
-  isNetworkDetailsToggleButtonDisabled,
 } = require("../selectors/index");
 const { autocompleteProvider } = require("../utils/filter-autocomplete-provider");
 const { L10N } = require("../utils/l10n");
 const { fetchNetworkUpdatePacket } = require("../utils/request-utils");
 
 // Components
 const SearchBox = createFactory(require("devtools/client/shared/components/SearchBox"));
 
 const { button, div, input, label, span } = dom;
 
 // Localization
-const COLLAPSE_DETAILS_PANE = L10N.getStr("collapseDetailsPane");
-const EXPAND_DETAILS_PANE = L10N.getStr("expandDetailsPane");
 const SEARCH_KEY_SHORTCUT = L10N.getStr("netmonitor.toolbar.filterFreetext.key");
 const SEARCH_PLACE_HOLDER = L10N.getStr("netmonitor.toolbar.filterFreetext.label");
 const TOOLBAR_CLEAR = L10N.getStr("netmonitor.toolbar.clear");
 const TOOLBAR_TOGGLE_RECORDING = L10N.getStr("netmonitor.toolbar.toggleRecording");
 
 // Preferences
 const DEVTOOLS_DISABLE_CACHE_PREF = "devtools.cache.disabled";
 const DEVTOOLS_ENABLE_PERSISTENT_LOG_PREF = "devtools.netmonitor.persistlog";
@@ -56,19 +53,16 @@ class Toolbar extends Component {
   static get propTypes() {
     return {
       connector: PropTypes.object.isRequired,
       toggleRecording: PropTypes.func.isRequired,
       recording: PropTypes.bool.isRequired,
       clearRequests: PropTypes.func.isRequired,
       requestFilterTypes: PropTypes.object.isRequired,
       setRequestFilterText: PropTypes.func.isRequired,
-      networkDetailsToggleDisabled: PropTypes.bool.isRequired,
-      networkDetailsOpen: PropTypes.bool.isRequired,
-      toggleNetworkDetails: PropTypes.func.isRequired,
       enablePersistentLogs: PropTypes.func.isRequired,
       togglePersistentLogs: PropTypes.func.isRequired,
       persistentLogsEnabled: PropTypes.bool.isRequired,
       disableBrowserCache: PropTypes.func.isRequired,
       toggleBrowserCache: PropTypes.func.isRequired,
       browserCacheDisabled: PropTypes.bool.isRequired,
       toggleRequestFilterType: PropTypes.func.isRequired,
       filteredRequests: PropTypes.array.isRequired,
@@ -87,19 +81,17 @@ class Toolbar extends Component {
   componentDidMount() {
     Services.prefs.addObserver(DEVTOOLS_ENABLE_PERSISTENT_LOG_PREF,
                                this.updatePersistentLogsEnabled);
     Services.prefs.addObserver(DEVTOOLS_DISABLE_CACHE_PREF,
                                this.updateBrowserCacheDisabled);
   }
 
   shouldComponentUpdate(nextProps) {
-    return this.props.networkDetailsOpen !== nextProps.networkDetailsOpen
-    || this.props.networkDetailsToggleDisabled !== nextProps.networkDetailsToggleDisabled
-    || this.props.persistentLogsEnabled !== nextProps.persistentLogsEnabled
+    return this.props.persistentLogsEnabled !== nextProps.persistentLogsEnabled
     || this.props.browserCacheDisabled !== nextProps.browserCacheDisabled
     || this.props.recording !== nextProps.recording
     || !Object.is(this.props.requestFilterTypes, nextProps.requestFilterTypes)
 
     // Filtered requests are useful only when searchbox is focused
     || !!(this.refs.searchbox && this.refs.searchbox.focused);
   }
 
@@ -144,19 +136,16 @@ class Toolbar extends Component {
   }
 
   render() {
     let {
       toggleRecording,
       clearRequests,
       requestFilterTypes,
       setRequestFilterText,
-      networkDetailsToggleDisabled,
-      networkDetailsOpen,
-      toggleNetworkDetails,
       togglePersistentLogs,
       persistentLogsEnabled,
       toggleBrowserCache,
       browserCacheDisabled,
       recording,
     } = this.props;
 
     // Render list of filter-buttons.
@@ -181,29 +170,16 @@ class Toolbar extends Component {
     // Calculate class-list for toggle recording button. The button
     // has two states: pause/play.
     let toggleRecordingButtonClass = [
       "devtools-button",
       "requests-list-pause-button",
       recording ? "devtools-pause-icon" : "devtools-play-icon",
     ].join(" ");
 
-    // Detail toggle button
-    let toggleDetailButtonClassList = [
-      "network-details-panel-toggle",
-      "devtools-button",
-    ];
-
-    if (!networkDetailsOpen) {
-      toggleDetailButtonClassList.push("pane-collapsed");
-    }
-    let toggleDetailButtonClass = toggleDetailButtonClassList.join(" ");
-    let toggleDetailButtonTitle = networkDetailsOpen ? COLLAPSE_DETAILS_PANE :
-      EXPAND_DETAILS_PANE;
-
     // Render the entire toolbar.
     return (
       span({ className: "devtools-toolbar devtools-toolbar-container" },
         span({ className: "devtools-toolbar-group" },
           button({
             className: toggleRecordingButtonClass,
             title: TOOLBAR_TOGGLE_RECORDING,
             onClick: toggleRecording,
@@ -248,44 +224,34 @@ class Toolbar extends Component {
             delay: FILTER_SEARCH_DELAY,
             keyShortcut: SEARCH_KEY_SHORTCUT,
             placeholder: SEARCH_PLACE_HOLDER,
             type: "filter",
             ref: "searchbox",
             onChange: setRequestFilterText,
             onFocus: this.onSearchBoxFocus,
             autocompleteProvider: this.autocompleteProvider,
-          }),
-          button({
-            className: toggleDetailButtonClass,
-            title: toggleDetailButtonTitle,
-            disabled: networkDetailsToggleDisabled,
-            tabIndex: "0",
-            onClick: toggleNetworkDetails,
-          }),
+          })
         )
       )
     );
   }
 }
 
 module.exports = connect(
   (state) => ({
     browserCacheDisabled: state.ui.browserCacheDisabled,
     filteredRequests: getTypeFilteredRequests(state),
-    networkDetailsToggleDisabled: isNetworkDetailsToggleButtonDisabled(state),
-    networkDetailsOpen: state.ui.networkDetailsOpen,
     persistentLogsEnabled: state.ui.persistentLogsEnabled,
     recording: getRecordingState(state),
     requestFilterTypes: state.filters.requestFilterTypes,
   }),
   (dispatch) => ({
     clearRequests: () => dispatch(Actions.clearRequests()),
     disableBrowserCache: (disabled) => dispatch(Actions.disableBrowserCache(disabled)),
     enablePersistentLogs: (enabled) => dispatch(Actions.enablePersistentLogs(enabled)),
     setRequestFilterText: (text) => dispatch(Actions.setRequestFilterText(text)),
     toggleBrowserCache: () => dispatch(Actions.toggleBrowserCache()),
-    toggleNetworkDetails: () => dispatch(Actions.toggleNetworkDetails()),
     toggleRecording: () => dispatch(Actions.toggleRecording()),
     togglePersistentLogs: () => dispatch(Actions.togglePersistentLogs()),
     toggleRequestFilterType: (type) => dispatch(Actions.toggleRequestFilterType(type)),
   }),
 )(Toolbar);
--- a/devtools/client/netmonitor/src/selectors/ui.js
+++ b/devtools/client/netmonitor/src/selectors/ui.js
@@ -1,24 +1,19 @@
 /* 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 { createSelector } = require("devtools/client/shared/vendor/reselect");
 const { REQUESTS_WATERFALL } = require("../constants");
-const { getDisplayedRequests } = require("./requests");
 
 const EPSILON = 0.001;
 
-function isNetworkDetailsToggleButtonDisabled(state) {
-  return getDisplayedRequests(state).length == 0;
-}
-
 const getWaterfallScale = createSelector(
   state => state.requests,
   state => state.timingMarkers,
   state => state.ui,
   (requests, timingMarkers, ui) => {
     if (requests.firstStartedMillis === +Infinity || ui.waterfallWidth === null) {
       return null;
     }
@@ -31,11 +26,10 @@ const getWaterfallScale = createSelector
   // Reduce 20px for the last request's requests-list-timings-total
     return Math.min(Math.max(
       (ui.waterfallWidth - REQUESTS_WATERFALL.LABEL_WIDTH - 20) / longestWidth,
       EPSILON), 1);
   }
 );
 
 module.exports = {
-  isNetworkDetailsToggleButtonDisabled,
   getWaterfallScale,
 };
--- a/devtools/client/netmonitor/test/browser_net_brotli.js
+++ b/devtools/client/netmonitor/test/browser_net_brotli.js
@@ -44,18 +44,17 @@ add_task(async function() {
       fullMimeType: "text/plain",
       transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 60),
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 64),
       time: true
     });
 
   wait = waitForDOM(document, ".CodeMirror-code");
   let onResponseContent = monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_CONTENT);
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
   await onResponseContent;
   await testResponse("br");
   await teardown(monitor);
 
   function testResponse(type) {
--- a/devtools/client/netmonitor/test/browser_net_clear.js
+++ b/devtools/client/netmonitor/test/browser_net_clear.js
@@ -8,17 +8,16 @@
  */
 
 add_task(async function() {
   let { tab, monitor } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
   let { document, store, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
-  let detailsPanelToggleButton = document.querySelector(".network-details-panel-toggle");
   let clearButton = document.querySelector(".requests-list-clear-button");
 
   store.dispatch(Actions.batchEnable(false));
 
   // Make sure we start in a sane state
   assertNoRequestState();
 
   // Load one request and assert it shows up in the list
@@ -35,43 +34,39 @@ add_task(async function() {
   // Load a second request and make sure they still show up
   onMonitorUpdated = waitForAllRequestsFinished(monitor);
   tab.linkedBrowser.reload();
   await onMonitorUpdated;
 
   assertSingleRequestState();
 
   // Make sure we can now open the network details panel
-  EventUtils.sendMouseEvent({ type: "click" }, detailsPanelToggleButton);
-
-  ok(document.querySelector(".network-details-panel") &&
+  store.dispatch(Actions.toggleNetworkDetails());
+  let detailsPanelToggleButton = document.querySelector(".sidebar-toggle");
+  ok(detailsPanelToggleButton &&
     !detailsPanelToggleButton.classList.contains("pane-collapsed"),
-    "The details pane should be visible after clicking the toggle button.");
+    "The details pane should be visible.");
 
   // Click clear and make sure the details pane closes
   EventUtils.sendMouseEvent({ type: "click" }, clearButton);
 
   assertNoRequestState();
   ok(!document.querySelector(".network-details-panel"),
     "The details pane should not be visible clicking 'clear'.");
 
   return teardown(monitor);
 
   /**
    * Asserts the state of the network monitor when one request has loaded
    */
   function assertSingleRequestState() {
     is(store.getState().requests.requests.size, 1,
       "The request menu should have one item at this point.");
-    is(detailsPanelToggleButton.hasAttribute("disabled"), false,
-      "The pane toggle button should be enabled after a request is made.");
   }
 
   /**
    * Asserts the state of the network monitor when no requests have loaded
    */
   function assertNoRequestState() {
     is(store.getState().requests.requests.size, 0,
       "The request menu should be empty at this point.");
-    is(detailsPanelToggleButton.hasAttribute("disabled"), true,
-      "The pane toggle button should be disabled when the request menu is cleared.");
   }
 });
--- a/devtools/client/netmonitor/test/browser_net_json-b64.js
+++ b/devtools/client/netmonitor/test/browser_net_json-b64.js
@@ -16,18 +16,17 @@ add_task(async function() {
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   // Execute requests.
   await performRequests(monitor, tab, 1);
 
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   let tabpanel = document.querySelector("#response-panel");
 
   is(tabpanel.querySelector(".response-error-header") === null, true,
     "The response error header doesn't have the intended visibility.");
--- a/devtools/client/netmonitor/test/browser_net_json-long.js
+++ b/devtools/client/netmonitor/test/browser_net_json-long.js
@@ -46,18 +46,17 @@ add_task(async function() {
       type: "json",
       fullMimeType: "text/json; charset=utf-8",
       size: L10N.getFormatStr("networkMenu.sizeKB",
         L10N.numberWithDecimals(85975 / 1024, 2)),
       time: true
     });
 
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   testResponseTab();
 
   await teardown(monitor);
 
--- a/devtools/client/netmonitor/test/browser_net_json-malformed.js
+++ b/devtools/client/netmonitor/test/browser_net_json-malformed.js
@@ -38,18 +38,17 @@ add_task(async function() {
     {
       status: 200,
       statusText: "OK",
       type: "json",
       fullMimeType: "text/json; charset=utf-8"
     });
 
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   let tabpanel = document.querySelector("#response-panel");
   is(tabpanel.querySelector(".response-error-header") === null, false,
     "The response error header doesn't have the intended visibility.");
   is(tabpanel.querySelector(".response-error-header").textContent,
--- a/devtools/client/netmonitor/test/browser_net_json-null.js
+++ b/devtools/client/netmonitor/test/browser_net_json-null.js
@@ -15,17 +15,22 @@ add_task(async function() {
   let { L10N } = windowRequire("devtools/client/netmonitor/src/utils/l10n");
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   // Execute requests.
   await performRequests(monitor, tab, 1);
 
-  await openResponsePanel();
+  let onReponsePanelReady = waitForDOM(document, "#response-panel .CodeMirror-code");
+  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector("#response-tab"));
+  await onReponsePanelReady;
+
   checkResponsePanelDisplaysJSON();
 
   let tabpanel = document.querySelector("#response-panel");
   is(tabpanel.querySelectorAll(".tree-section").length, 2,
     "There should be 2 tree sections displayed in this tabpanel.");
   is(tabpanel.querySelectorAll(".treeRow:not(.tree-section)").length, 1,
     "There should be 1 json properties displayed in this tabpanel.");
   is(tabpanel.querySelectorAll(".empty-notice").length, 0,
@@ -52,22 +57,9 @@ add_task(async function() {
     let jsonView = panel.querySelector(".tree-section .treeLabel") || {};
     is(jsonView.textContent === L10N.getStr("jsonScopeName"), true,
       "The response json view has the intended visibility.");
     is(panel.querySelector(".CodeMirror-code") === null, false,
       "The response editor has the intended visibility.");
     is(panel.querySelector(".response-image-box") === null, true,
       "The response image box doesn't have the intended visibility.");
   }
-
-  /**
-   * Open the netmonitor details panel and switch to the response tab.
-   * Returns a promise that will resolve when the response panel DOM element is available.
-   */
-  function openResponsePanel() {
-    let onReponsePanelReady = waitForDOM(document, "#response-panel .CodeMirror-code");
-    EventUtils.sendMouseEvent({ type: "click" },
-      document.querySelector(".network-details-panel-toggle"));
-    EventUtils.sendMouseEvent({ type: "click" },
-      document.querySelector("#response-tab"));
-    return onReponsePanelReady;
-  }
 });
--- a/devtools/client/netmonitor/test/browser_net_json_custom_mime.js
+++ b/devtools/client/netmonitor/test/browser_net_json_custom_mime.js
@@ -40,18 +40,17 @@ add_task(async function() {
       statusText: "OK",
       type: "x-bigcorp-json",
       fullMimeType: "text/x-bigcorp-json; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 41),
       time: true
     });
 
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   testResponseTab();
 
   await teardown(monitor);
 
--- a/devtools/client/netmonitor/test/browser_net_json_text_mime.js
+++ b/devtools/client/netmonitor/test/browser_net_json_text_mime.js
@@ -41,18 +41,17 @@ add_task(async function() {
       statusText: "OK",
       type: "plain",
       fullMimeType: "text/plain; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 41),
       time: true
     });
 
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   testResponseTab();
 
   await teardown(monitor);
 
--- a/devtools/client/netmonitor/test/browser_net_jsonp.js
+++ b/devtools/client/netmonitor/test/browser_net_jsonp.js
@@ -59,18 +59,17 @@ add_task(async function() {
       type: "json",
       fullMimeType: "text/json; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 54),
       time: true
     });
 
   info("Testing first request");
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   testResponseTab("$_0123Fun", "Hello JSONP!");
 
   info("Testing second request");
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
--- a/devtools/client/netmonitor/test/browser_net_large-response.js
+++ b/devtools/client/netmonitor/test/browser_net_large-response.js
@@ -45,18 +45,17 @@ add_task(async function() {
     "GET",
     CONTENT_TYPE_SJS + "?fmt=html-long",
     {
       status: 200,
       statusText: "OK"
     });
 
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   let text = document.querySelector(".CodeMirror-line").textContent;
 
   ok(text.match(/^<p>/), "The text shown in the source editor is incorrect.");
 
--- a/devtools/client/netmonitor/test/browser_net_pane-collapse.js
+++ b/devtools/client/netmonitor/test/browser_net_pane-collapse.js
@@ -6,46 +6,47 @@
 /**
  * Tests if the network monitor panes collapse properly.
  */
 
 add_task(async function() {
   let { tab, monitor } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
-  let { document, windowRequire } = monitor.panelWin;
+  let { document, store, windowRequire } = monitor.panelWin;
+  let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   let { Prefs } = windowRequire("devtools/client/netmonitor/src/utils/prefs");
-  let detailsPaneToggleButton = document.querySelector(".network-details-panel-toggle");
 
   let wait = waitForNetworkEvents(monitor, 1);
   tab.linkedBrowser.reload();
   await wait;
 
   ok(!document.querySelector(".network-details-panel") &&
-     detailsPaneToggleButton.classList.contains("pane-collapsed"),
+     !document.querySelector(".sidebar-toggle"),
     "The details panel should initially be hidden.");
 
-  EventUtils.sendMouseEvent({ type: "click" }, detailsPaneToggleButton);
+  store.dispatch(Actions.toggleNetworkDetails());
 
   is(~~(document.querySelector(".network-details-panel").clientWidth),
     Prefs.networkDetailsWidth,
     "The details panel has an incorrect width.");
   ok(document.querySelector(".network-details-panel") &&
-     !detailsPaneToggleButton.classList.contains("pane-collapsed"),
+     document.querySelector(".sidebar-toggle"),
     "The details panel should at this point be visible.");
 
-  EventUtils.sendMouseEvent({ type: "click" }, detailsPaneToggleButton);
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".sidebar-toggle"));
 
   ok(!document.querySelector(".network-details-panel") &&
-     detailsPaneToggleButton.classList.contains("pane-collapsed"),
+     !document.querySelector(".sidebar-toggle"),
     "The details panel should not be visible after collapsing.");
 
-  EventUtils.sendMouseEvent({ type: "click" }, detailsPaneToggleButton);
+  store.dispatch(Actions.toggleNetworkDetails());
 
   is(~~(document.querySelector(".network-details-panel").clientWidth),
     Prefs.networkDetailsWidth,
     "The details panel has an incorrect width after uncollapsing.");
   ok(document.querySelector(".network-details-panel") &&
-     !detailsPaneToggleButton.classList.contains("pane-collapsed"),
+     document.querySelector(".sidebar-toggle"),
     "The details panel should be visible again after uncollapsing.");
 
   await teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_pane-toggle.js
+++ b/devtools/client/netmonitor/test/browser_net_pane-toggle.js
@@ -16,63 +16,50 @@ add_task(async function() {
   let { EVENTS } = windowRequire("devtools/client/netmonitor/src/constants");
   let {
     getSelectedRequest,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   store.dispatch(Actions.batchEnable(false));
 
-  let toggleButton = document.querySelector(".network-details-panel-toggle");
-
-  is(toggleButton.hasAttribute("disabled"), true,
-    "The pane toggle button should be disabled when the frontend is opened.");
-  is(toggleButton.classList.contains("pane-collapsed"), true,
-    "The pane toggle button should indicate that the details pane is " +
-    "collapsed when the frontend is opened.");
+  ok(!document.querySelector(".sidebar-toggle"),
+    "The pane toggle button should not be visible.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The details pane should be hidden when the frontend is opened.");
   is(getSelectedRequest(store.getState()), null,
     "There should be no selected item in the requests menu.");
 
   let networkEvent = monitor.panelWin.once(EVENTS.NETWORK_EVENT);
   tab.linkedBrowser.reload();
   await networkEvent;
 
-  is(toggleButton.hasAttribute("disabled"), false,
-    "The pane toggle button should be enabled after the first request.");
-  is(toggleButton.classList.contains("pane-collapsed"), true,
-    "The pane toggle button should still indicate that the details pane is " +
-    "collapsed after the first request.");
+  ok(!document.querySelector(".sidebar-toggle"),
+    "The pane toggle button should not be visible after the first request.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The details pane should still be hidden after the first request.");
   is(getSelectedRequest(store.getState()), null,
     "There should still be no selected item in the requests menu.");
 
-  EventUtils.sendMouseEvent({ type: "click" }, toggleButton);
+  store.dispatch(Actions.toggleNetworkDetails());
 
-  is(toggleButton.hasAttribute("disabled"), false,
-    "The pane toggle button should still be enabled after being pressed.");
+  let toggleButton = document.querySelector(".sidebar-toggle");
+
   is(toggleButton.classList.contains("pane-collapsed"), false,
     "The pane toggle button should now indicate that the details pane is " +
-    "not collapsed anymore after being pressed.");
+    "not collapsed anymore.");
   is(!!document.querySelector(".network-details-panel"), true,
     "The details pane should not be hidden after toggle button was pressed.");
   isnot(getSelectedRequest(store.getState()), null,
     "There should be a selected item in the requests menu.");
   is(getSelectedIndex(store.getState()), 0,
     "The first item should be selected in the requests menu.");
 
   EventUtils.sendMouseEvent({ type: "click" }, toggleButton);
 
-  is(toggleButton.hasAttribute("disabled"), false,
-    "The pane toggle button should still be enabled after being pressed again.");
-  is(toggleButton.classList.contains("pane-collapsed"), true,
-    "The pane toggle button should now indicate that the details pane is " +
-    "collapsed after being pressed again.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The details pane should now be hidden after the toggle button was pressed again.");
   is(getSelectedRequest(store.getState()), null,
     "There should now be no selected item in the requests menu.");
 
   await teardown(monitor);
 
   function getSelectedIndex(state) {
--- a/devtools/client/netmonitor/test/browser_net_post-data-03.js
+++ b/devtools/client/netmonitor/test/browser_net_post-data-03.js
@@ -19,18 +19,17 @@ add_task(async function() {
 
   store.dispatch(Actions.batchEnable(false));
 
   // Execute requests.
   await performRequests(monitor, tab, 1);
 
   // Wait for all tree view updated by react
   wait = waitForDOM(document, "#headers-panel .tree-section .treeLabel", 3);
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#headers-tab"));
   await wait;
 
   let tabpanel = document.querySelector("#headers-panel");
   is(tabpanel.querySelectorAll(".tree-section .treeLabel").length, 3,
     "There should be 3 header sections displayed in this tabpanel.");
 
--- a/devtools/client/netmonitor/test/browser_net_post-data-04.js
+++ b/devtools/client/netmonitor/test/browser_net_post-data-04.js
@@ -19,18 +19,17 @@ add_task(async function() {
 
   store.dispatch(Actions.batchEnable(false));
 
   // Execute requests.
   await performRequests(monitor, tab, 1);
 
   // Wait for all tree view updated by react
   wait = waitForDOM(document, "#params-panel .tree-section");
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#params-tab"));
   await wait;
 
   let tabpanel = document.querySelector("#params-panel");
 
   ok(tabpanel.querySelector(".treeTable"),
     "The request params doesn't have the indended visibility.");
--- a/devtools/client/netmonitor/test/browser_net_prefs-reload.js
+++ b/devtools/client/netmonitor/test/browser_net_prefs-reload.js
@@ -179,18 +179,17 @@ add_task(async function() {
     let newMonitor = await restartNetMonitor(monitor);
     monitor = newMonitor.monitor;
 
     let networkEvent = waitForNetworkEvents(monitor, 1);
     newMonitor.tab.linkedBrowser.reload();
     await networkEvent;
 
     let wait = waitForDOM(getDoc(), ".network-details-panel");
-    EventUtils.sendMouseEvent({ type: "click" },
-      getDoc().querySelector(".network-details-panel-toggle"));
+    getStore().dispatch(Actions.toggleNetworkDetails());
     await wait;
   }
 
   async function testBottom() {
     await restartNetMonitorAndSetupEnv();
 
     info("Testing prefs reload for a bottom host.");
     storeFirstPrefValues();
--- a/devtools/client/netmonitor/test/browser_net_security-details.js
+++ b/devtools/client/netmonitor/test/browser_net_security-details.js
@@ -19,18 +19,17 @@ add_task(async function() {
   info("Performing a secure request.");
   const REQUESTS_URL = "https://example.com" + CORS_SJS_PATH;
   let wait = waitForNetworkEvents(monitor, 1);
   await ContentTask.spawn(tab.linkedBrowser, REQUESTS_URL, async function(url) {
     content.wrappedJSObject.performRequests(1, url);
   });
   await wait;
 
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#security-tab"));
   await waitUntil(() => document.querySelector(
     "#security-panel .security-info-value"));
 
   let tabpanel = document.querySelector("#security-panel");
   let textboxes = tabpanel.querySelectorAll(".textbox-input");
 
--- a/devtools/client/netmonitor/test/browser_net_security-error.js
+++ b/devtools/client/netmonitor/test/browser_net_security-error.js
@@ -18,18 +18,17 @@ add_task(async function() {
 
   let requestsDone = waitForNetworkEvents(monitor, 1);
   await ContentTask.spawn(tab.linkedBrowser, {}, async function() {
     content.wrappedJSObject.performRequests(1, "https://nocert.example.com");
   });
   await requestsDone;
 
   let securityInfoLoaded = waitForDOM(document, ".security-info-value");
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
 
   await waitUntil(() => document.querySelector("#security-tab"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#security-tab"));
   await securityInfoLoaded;
 
   let errormsg = document.querySelector(".security-info-value");
   isnot(errormsg.textContent, "", "Error message is not empty.");
--- a/devtools/client/netmonitor/test/browser_net_simple-request-details.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request-details.js
@@ -30,18 +30,17 @@ add_task(async function() {
 
   is(getSelectedRequest(store.getState()), undefined,
     "There shouldn't be any selected item in the requests menu.");
   is(store.getState().requests.requests.size, 1,
     "The requests menu should not be empty after the first request.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The network details panel should still be hidden after first request.");
 
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
 
   isnot(getSelectedRequest(store.getState()), undefined,
     "There should be a selected item in the requests menu.");
   is(getSelectedIndex(store.getState()), 0,
     "The first item should be selected in the requests menu.");
   is(!!document.querySelector(".network-details-panel"), true,
     "The network details panel should not be hidden after toggle button was pressed.");
 
--- a/devtools/client/netmonitor/test/browser_net_simple-request.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request.js
@@ -16,55 +16,43 @@ add_task(async function() {
   let { tab, monitor } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
   let { document, store, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
 
   store.dispatch(Actions.batchEnable(false));
 
-  is(document.querySelector(".network-details-panel-toggle").hasAttribute("disabled"),
-    true,
-    "The pane toggle button should be disabled when the frontend is opened.");
   ok(document.querySelector(".request-list-empty-notice"),
     "An empty notice should be displayed when the frontend is opened.");
   is(store.getState().requests.requests.size, 0,
     "The requests menu should be empty when the frontend is opened.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The network details panel should be hidden when the frontend is opened.");
 
   await reloadAndWait();
 
-  is(document.querySelector(".network-details-panel-toggle").hasAttribute("disabled"),
-    false,
-    "The pane toggle button should be enabled after the first request.");
   ok(!document.querySelector(".request-list-empty-notice"),
     "The empty notice should be hidden after the first request.");
   is(store.getState().requests.requests.size, 1,
     "The requests menu should not be empty after the first request.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The network details panel should still be hidden after the first request.");
 
   await reloadAndWait();
 
-  is(document.querySelector(".network-details-panel-toggle").hasAttribute("disabled"),
-    false,
-    "The pane toggle button should be still be enabled after a reload.");
   ok(!document.querySelector(".request-list-empty-notice"),
     "The empty notice should be still hidden after a reload.");
   is(store.getState().requests.requests.size, 1,
     "The requests menu should not be empty after a reload.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The network details panel should still be hidden after a reload.");
 
   store.dispatch(Actions.clearRequests());
 
-  is(document.querySelector(".network-details-panel-toggle").hasAttribute("disabled"),
-    true,
-    "The pane toggle button should be disabled when after clear.");
   ok(document.querySelector(".request-list-empty-notice"),
     "An empty notice should be displayed again after clear.");
   is(store.getState().requests.requests.size, 0,
     "The requests menu should be empty after clear.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The network details panel should still be hidden after clear.");
 
   return teardown(monitor);
--- a/devtools/client/netmonitor/test/browser_net_sort-01.js
+++ b/devtools/client/netmonitor/test/browser_net_sort-01.js
@@ -46,18 +46,17 @@ add_task(async function() {
     url: "sjs_sorting-test-server.sjs?index=3&" + Math.random(),
     method: "GET3"
   }];
 
   let wait = waitForNetworkEvents(monitor, 5);
   await performRequestsInContent(requests);
   await wait;
 
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
 
   isnot(getSelectedRequest(store.getState()), undefined,
     "There should be a selected item in the requests menu.");
   is(getSelectedIndex(store.getState()), 0,
     "The first item should be selected in the requests menu.");
   is(!!document.querySelector(".network-details-panel"), true,
     "The network details panel should be visible after toggle button was pressed.");
 
--- a/devtools/client/netmonitor/test/browser_net_sort-02.js
+++ b/devtools/client/netmonitor/test/browser_net_sort-02.js
@@ -46,18 +46,17 @@ add_task(async function() {
     url: "sjs_sorting-test-server.sjs?index=3&" + Math.random(),
     method: "GET3"
   }];
 
   let wait = waitForNetworkEvents(monitor, 5);
   await performRequestsInContent(requests);
   await wait;
 
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
 
   isnot(getSelectedRequest(store.getState()), undefined,
     "There should be a selected item in the requests menu.");
   is(getSelectedIndex(store.getState()), 0,
     "The first item should be selected in the requests menu.");
   is(!!document.querySelector(".network-details-panel"), true,
     "The network details panel should be visible after toggle button was pressed.");
 
--- a/devtools/client/netmonitor/test/browser_net_streaming-response.js
+++ b/devtools/client/netmonitor/test/browser_net_streaming-response.js
@@ -52,18 +52,17 @@ add_task(async function() {
       CONTENT_TYPE_SJS + "?fmt=" + fmt,
       {
         status: 200,
         statusText: "OK"
       });
   });
 
   wait = waitForDOM(document, "#response-panel");
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".network-details-panel-toggle"));
+  store.dispatch(Actions.toggleNetworkDetails());
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   store.dispatch(Actions.selectRequest(null));
 
   await selectIndexAndWaitForSourceEditor(monitor, 0);
   // the hls-m3u8 part