From e329d92b5fc06ff74c17017ec223a06b0611a867 Mon Sep 17 00:00:00 2001 From: Ricky Chien Date: Sat, 11 Feb 2017 09:34:53 +0800 Subject: [PATCH] Bug 1309183 - Replace XUL Splitter by SplitBox r=Honza MozReview-Commit-ID: Lm6Y8JdF9Ga --HG-- extra : rebase_source : ef8014dde11a53026e0b702dd375ac309b9db565 --- ...browser_ignore_toolbox_network_requests.js | 1 - devtools/client/netmonitor/.eslintrc.js | 4 + .../netmonitor/components/monitor-panel.js | 145 ++++++++++++ .../client/netmonitor/components/moz.build | 3 +- .../components/request-list-content.js | 10 +- .../components/request-list-header.js | 27 ++- .../netmonitor/components/request-list.js | 114 ++-------- .../netmonitor/components/statistics-panel.js | 14 +- .../client/netmonitor/components/toolbar.js | 214 +++++++++--------- .../test/browser_net_har_copy_all_as_har.js | 2 +- .../har/test/browser_net_har_post_data.js | 2 +- .../test/browser_net_har_throttle_upload.js | 2 +- .../client/netmonitor/middleware/prefs.js | 6 +- devtools/client/netmonitor/moz.build | 2 + .../netmonitor/netmonitor-controller.js | 7 +- devtools/client/netmonitor/netmonitor-view.js | 32 +-- devtools/client/netmonitor/netmonitor.js | 22 +- devtools/client/netmonitor/netmonitor.xul | 28 +-- devtools/client/netmonitor/reducers/ui.js | 5 + .../request-list-context-menu.js | 6 +- .../{components => }/request-list-tooltip.js | 4 +- .../client/netmonitor/selectors/filters.js | 7 +- .../client/netmonitor/selectors/requests.js | 2 +- .../components/network-details-panel.js | 105 ++++----- devtools/client/netmonitor/test/browser.ini | 1 - .../test/browser_net_complex-params.js | 21 +- .../test/browser_net_prefs-reload.js | 165 ++++++++------ .../test/browser_net_statistics-01.js | 2 +- .../test/browser_net_statistics-02.js | 2 +- .../shared/components/splitter/split-box.js | 20 +- .../client/shared/components/tabs/tabbar.js | 2 +- devtools/client/themes/netmonitor.css | 58 ++--- 32 files changed, 518 insertions(+), 517 deletions(-) create mode 100644 devtools/client/netmonitor/components/monitor-panel.js rename devtools/client/netmonitor/{components => }/request-list-context-menu.js (99%) rename devtools/client/netmonitor/{components => }/request-list-tooltip.js (97%) diff --git a/devtools/client/framework/test/browser_ignore_toolbox_network_requests.js b/devtools/client/framework/test/browser_ignore_toolbox_network_requests.js index 903d757bcb2e..a5c30e44db13 100644 --- a/devtools/client/framework/test/browser_ignore_toolbox_network_requests.js +++ b/devtools/client/framework/test/browser_ignore_toolbox_network_requests.js @@ -24,7 +24,6 @@ add_task(function* () { let monitor = yield toolbox.selectTool("netmonitor"); let { gStore, windowRequire } = monitor.panelWin; - let Actions = windowRequire("devtools/client/netmonitor/actions/index"); is(gStore.getState().requests.requests.size, 0, "No network requests appear in the network panel"); diff --git a/devtools/client/netmonitor/.eslintrc.js b/devtools/client/netmonitor/.eslintrc.js index 28b599479bf8..a7326d498044 100644 --- a/devtools/client/netmonitor/.eslintrc.js +++ b/devtools/client/netmonitor/.eslintrc.js @@ -5,6 +5,10 @@ "use strict"; module.exports = { + "env": { + "browser": true, + }, + // Extend from the devtools eslintrc. "extends": "../../.eslintrc.js", diff --git a/devtools/client/netmonitor/components/monitor-panel.js b/devtools/client/netmonitor/components/monitor-panel.js new file mode 100644 index 000000000000..84bea0bacbd4 --- /dev/null +++ b/devtools/client/netmonitor/components/monitor-panel.js @@ -0,0 +1,145 @@ +/* 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/. */ + +/* globals gNetwork, NetMonitorController */ + +"use strict"; + +const { + createClass, + createFactory, + DOM, + PropTypes, +} = require("devtools/client/shared/vendor/react"); +const { connect } = require("devtools/client/shared/vendor/react-redux"); +const { findDOMNode } = require("devtools/client/shared/vendor/react-dom"); +const Actions = require("../actions/index"); +const { Prefs } = require("../prefs"); +const { getFormDataSections } = require("../request-utils"); +const { getSelectedRequest } = require("../selectors/index"); + +// Components +const SplitBox = createFactory(require("devtools/client/shared/components/splitter/split-box")); +const NetworkDetailsPanel = createFactory(require("../shared/components/network-details-panel")); +const RequestList = createFactory(require("./request-list")); +const Toolbar = createFactory(require("./toolbar")); + +const { div } = DOM; +const MediaQueryList = window.matchMedia("(min-width: 700px)"); + +/* + * Monitor panel component + * The main panel for displaying various network request information + */ +const MonitorPanel = createClass({ + displayName: "MonitorPanel", + + propTypes: { + isEmpty: PropTypes.bool.isRequired, + networkDetailsOpen: PropTypes.bool.isRequired, + openNetworkDetails: PropTypes.func.isRequired, + request: PropTypes.object, + updateRequest: PropTypes.func.isRequired, + }, + + getInitialState() { + return { + isVerticalSpliter: MediaQueryList.matches, + }; + }, + + componentDidMount() { + MediaQueryList.addListener(this.onLayoutChange); + }, + + componentWillReceiveProps(nextProps) { + let { + openNetworkDetails, + request = {}, + updateRequest, + } = nextProps; + let { + formDataSections, + requestHeaders, + requestHeadersFromUploadStream, + requestPostData, + } = request; + + if (nextProps.isEmpty) { + openNetworkDetails(false); + } else if (nextProps.request && nextProps.request !== this.props.request) { + openNetworkDetails(true); + } + + if (!formDataSections && requestHeaders && + requestHeadersFromUploadStream && requestPostData) { + getFormDataSections( + requestHeaders, + requestHeadersFromUploadStream, + requestPostData, + gNetwork.getString.bind(gNetwork), + ).then((newFormDataSections) => { + updateRequest( + request.id, + { formDataSections: newFormDataSections }, + true, + ); + }); + } + }, + + componentWillUnmount() { + MediaQueryList.removeListener(this.onLayoutChange); + let { clientWidth, clientHeight } = findDOMNode(this.refs.networkDetailsPanel) || {}; + + if (this.state.isVerticalSpliter && clientWidth) { + Prefs.networkDetailsWidth = clientWidth; + } else if (clientHeight) { + Prefs.networkDetailsHeight = clientHeight; + } + }, + + onLayoutChange() { + this.setState({ + isVerticalSpliter: MediaQueryList.matches, + }); + }, + + render() { + let { isEmpty, networkDetailsOpen } = this.props; + return ( + div({ className: "monitor-panel" }, + Toolbar(), + SplitBox({ + className: "devtools-responsive-container split-box", + initialWidth: `${Prefs.networkDetailsWidth}px`, + initialHeight: `${Prefs.networkDetailsHeight}px`, + minSize: "50px", + maxSize: "80%", + splitterSize: "1px", + startPanel: RequestList({ isEmpty }), + endPanel: networkDetailsOpen ? + NetworkDetailsPanel({ + ref: "networkDetailsPanel", + toolbox: NetMonitorController._toolbox, + }) : null, + endPanelControl: true, + vert: this.state.isVerticalSpliter, + }), + ) + ); + } +}); + +module.exports = connect( + (state) => ({ + isEmpty: state.requests.requests.isEmpty(), + networkDetailsOpen: state.ui.networkDetailsOpen, + request: getSelectedRequest(state), + }), + (dispatch) => ({ + openNetworkDetails: (open) => dispatch(Actions.openNetworkDetails(open)), + updateRequest: (id, data, batch) => dispatch(Actions.updateRequest(id, data, batch)), + }), +)(MonitorPanel); diff --git a/devtools/client/netmonitor/components/moz.build b/devtools/client/netmonitor/components/moz.build index b0cda76879d2..1c135489262d 100644 --- a/devtools/client/netmonitor/components/moz.build +++ b/devtools/client/netmonitor/components/moz.build @@ -3,12 +3,11 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. DevToolsModules( + 'monitor-panel.js', 'request-list-content.js', - 'request-list-context-menu.js', 'request-list-empty.js', 'request-list-header.js', 'request-list-item.js', - 'request-list-tooltip.js', 'request-list.js', 'statistics-panel.js', 'toolbar.js', diff --git a/devtools/client/netmonitor/components/request-list-content.js b/devtools/client/netmonitor/components/request-list-content.js index 1aeb8976259b..308f0293afd5 100644 --- a/devtools/client/netmonitor/components/request-list-content.js +++ b/devtools/client/netmonitor/components/request-list-content.js @@ -20,7 +20,7 @@ const Actions = require("../actions/index"); const { setTooltipImageContent, setTooltipStackTraceContent, -} = require("./request-list-tooltip"); +} = require("../request-list-tooltip"); const { getDisplayedRequests, getWaterfallScale, @@ -28,7 +28,7 @@ const { // Components const RequestListItem = createFactory(require("./request-list-item")); -const RequestListContextMenu = require("./request-list-context-menu"); +const RequestListContextMenu = require("../request-list-context-menu"); const { div } = DOM; @@ -42,7 +42,6 @@ const RequestListContent = createClass({ displayName: "RequestListContent", propTypes: { - contextMenu: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, displayedRequests: PropTypes.object.isRequired, firstRequestStartedMillis: PropTypes.number.isRequired, @@ -51,11 +50,6 @@ const RequestListContent = createClass({ onSelectDelta: PropTypes.func.isRequired, scale: PropTypes.number, selectedRequestId: PropTypes.string, - tooltip: PropTypes.shape({ - hide: PropTypes.func.isRequired, - startTogglingOnHover: PropTypes.func.isRequired, - stopTogglingOnHover: PropTypes.func.isRequired, - }).isRequired }, componentWillMount() { diff --git a/devtools/client/netmonitor/components/request-list-header.js b/devtools/client/netmonitor/components/request-list-header.js index bd602d43d67b..e76b3263ca48 100644 --- a/devtools/client/netmonitor/components/request-list-header.js +++ b/devtools/client/netmonitor/components/request-list-header.js @@ -8,8 +8,8 @@ const { createClass, PropTypes, DOM } = require("devtools/client/shared/vendor/react"); const { div, button } = DOM; -const { findDOMNode } = require("devtools/client/shared/vendor/react-dom"); const { connect } = require("devtools/client/shared/vendor/react-redux"); +const { setNamedTimeout } = require("devtools/client/shared/widgets/view-helpers"); const { L10N } = require("../l10n"); const { getWaterfallScale } = require("../selectors/index"); const Actions = require("../actions/index"); @@ -50,19 +50,11 @@ const RequestListHeader = createClass({ }, componentDidMount() { - // This is the first time the waterfall column header is actually rendered. - // Measure its width and update the 'waterfallWidth' property in the store. - // The 'waterfallWidth' will be further updated on every window resize. - const waterfallHeaderEl = findDOMNode(this) - .querySelector("#requests-menu-waterfall-header-box"); - if (waterfallHeaderEl) { - const { width } = waterfallHeaderEl.getBoundingClientRect(); - this.props.resizeWaterfall(width); - } - // Create the object that takes care of drawing the waterfall canvas background this.background = new WaterfallBackground(document); this.background.draw(this.props); + this.resizeWaterfall(); + window.addEventListener("resize", this.resizeWaterfall); }, componentDidUpdate() { @@ -72,6 +64,16 @@ const RequestListHeader = createClass({ componentWillUnmount() { this.background.destroy(); this.background = null; + window.removeEventListener("resize", this.resizeWaterfall); + }, + + resizeWaterfall() { + // Measure its width and update the 'waterfallWidth' property in the store. + // The 'waterfallWidth' will be further updated on every window resize. + setNamedTimeout("resize-events", 50, () => { + const { width } = this.refs.header.getBoundingClientRect(); + this.props.resizeWaterfall(width); + }); }, render() { @@ -97,8 +99,9 @@ const RequestListHeader = createClass({ return div( { id: `requests-menu-${boxName}-header-box`, - key: name, className: `requests-menu-header requests-menu-${boxName}`, + key: name, + ref: "header", // Used to style the next column. "data-active": active, }, diff --git a/devtools/client/netmonitor/components/request-list.js b/devtools/client/netmonitor/components/request-list.js index 0ca2560e2927..de3c95bb1c85 100644 --- a/devtools/client/netmonitor/components/request-list.js +++ b/devtools/client/netmonitor/components/request-list.js @@ -2,26 +2,13 @@ * 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/. */ -/* eslint-env browser */ -/* globals gNetwork */ - "use strict"; const { - createClass, createFactory, DOM, PropTypes, } = require("devtools/client/shared/vendor/react"); -const { connect } = require("devtools/client/shared/vendor/react-redux"); -const { setNamedTimeout } = require("devtools/client/shared/widgets/view-helpers"); -const Actions = require("../actions/index"); -const { Prefs } = require("../prefs"); -const { getFormDataSections } = require("../request-utils"); -const { - getActiveFilters, - getSelectedRequest, -} = require("../selectors/index"); // Components const RequestListContent = createFactory(require("./request-list-content")); @@ -33,94 +20,19 @@ const { div } = DOM; /** * Request panel component */ -const RequestList = createClass({ - displayName: "RequestList", +function RequestList({ isEmpty }) { + return ( + div({ className: "request-list-container" }, + RequestListHeader(), + isEmpty ? RequestListEmptyNotice() : RequestListContent(), + ) + ); +} - propTypes: { - activeFilters: PropTypes.array, - dispatch: PropTypes.func, - isEmpty: PropTypes.bool.isRequired, - request: PropTypes.object, - networkDetailsOpen: PropTypes.bool, - }, +RequestList.displayName = "RequestList"; - componentDidMount() { - const { dispatch } = this.props; +RequestList.propTypes = { + isEmpty: PropTypes.bool.isRequired, +}; - Prefs.filters.forEach((type) => dispatch(Actions.toggleRequestFilterType(type))); - this.splitter = document.querySelector("#network-inspector-view-splitter"); - this.splitter.addEventListener("mouseup", this.resize); - window.addEventListener("resize", this.resize); - }, - - componentWillReceiveProps(nextProps) { - const { dispatch, request = {}, networkDetailsOpen } = this.props; - - if (nextProps.request && nextProps.request !== request) { - dispatch(Actions.openNetworkDetails(true)); - } - - if (nextProps.networkDetailsOpen !== networkDetailsOpen) { - this.resize(); - } - - const { - formDataSections, - requestHeaders, - requestHeadersFromUploadStream, - requestPostData, - } = nextProps.request || {}; - - if (!formDataSections && requestHeaders && - requestHeadersFromUploadStream && requestPostData) { - getFormDataSections( - requestHeaders, - requestHeadersFromUploadStream, - requestPostData, - gNetwork.getString.bind(gNetwork), - ).then((newFormDataSections) => { - dispatch(Actions.updateRequest( - request.id, - { formDataSections: newFormDataSections }, - true, - )); - }); - } - }, - - componentWillUnmount() { - this.splitter.removeEventListener("mouseup", this.resize); - window.removeEventListener("resize", this.resize); - }, - - resize() { - const { dispatch } = this.props; - // Allow requests to settle down first. - setNamedTimeout("resize-events", 50, () => { - const waterfallHeaderEl = - document.querySelector("#requests-menu-waterfall-header-box"); - if (waterfallHeaderEl) { - const { width } = waterfallHeaderEl.getBoundingClientRect(); - dispatch(Actions.resizeWaterfall(width)); - } - }); - }, - - render() { - return ( - div({ className: "request-list-container" }, - RequestListHeader(), - this.props.isEmpty ? RequestListEmptyNotice() : RequestListContent(), - ) - ); - } -}); - -module.exports = connect( - (state) => ({ - activeFilters: getActiveFilters(state), - isEmpty: state.requests.requests.isEmpty(), - request: getSelectedRequest(state), - networkDetailsOpen: state.ui.networkDetailsOpen, - }) -)(RequestList); +module.exports = RequestList; diff --git a/devtools/client/netmonitor/components/statistics-panel.js b/devtools/client/netmonitor/components/statistics-panel.js index 8c292fd5e3be..a679c928997b 100644 --- a/devtools/client/netmonitor/components/statistics-panel.js +++ b/devtools/client/netmonitor/components/statistics-panel.js @@ -2,8 +2,6 @@ * 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/. */ -/* globals document */ - "use strict"; const { @@ -53,13 +51,13 @@ const StatisticsPanel = createClass({ this.createChart({ id: "primedCacheChart", title: CHARTS_CACHE_ENABLED, - data: ready ? this.sanitizeChartDataSource(requests, false) : null + data: ready ? this.sanitizeChartDataSource(requests, false) : null, }); this.createChart({ id: "emptyCacheChart", title: CHARTS_CACHE_DISABLED, - data: ready ? this.sanitizeChartDataSource(requests, true) : null + data: ready ? this.sanitizeChartDataSource(requests, true) : null, }); }, @@ -74,7 +72,7 @@ const StatisticsPanel = createClass({ label: L10N.getStr("charts.type"), size: L10N.getStr("charts.size"), transferredSize: L10N.getStr("charts.transferred"), - time: L10N.getStr("charts.time") + time: L10N.getStr("charts.time"), }, data, strings: { @@ -84,7 +82,7 @@ const StatisticsPanel = createClass({ L10N.getFormatStr("charts.transferredSizeKB", getSizeWithDecimals(value / 1024)), time: (value) => - L10N.getFormatStr("charts.totalS", getTimeWithDecimals(value / 1000)) + L10N.getFormatStr("charts.totalS", getTimeWithDecimals(value / 1000)), }, totals: { cached: (total) => L10N.getFormatStr("charts.totalCached", total), @@ -129,7 +127,7 @@ const StatisticsPanel = createClass({ label: type, size: 0, transferredSize: 0, - time: 0 + time: 0, })); for (let request of requests) { @@ -224,7 +222,7 @@ const StatisticsPanel = createClass({ return ( div({ className: "statistics-panel" }, button({ - className: "back-button devtools-toolbarbutton", + className: "back-button devtools-button", "data-text-only": "true", title: BACK_BUTTON, onClick: closeStatistics, diff --git a/devtools/client/netmonitor/components/toolbar.js b/devtools/client/netmonitor/components/toolbar.js index ef82f80a9396..404a9b9e728d 100644 --- a/devtools/client/netmonitor/components/toolbar.js +++ b/devtools/client/netmonitor/components/toolbar.js @@ -5,6 +5,7 @@ "use strict"; const { + createClass, createFactory, DOM, PropTypes, @@ -13,8 +14,10 @@ const { connect } = require("devtools/client/shared/vendor/react-redux"); const { PluralForm } = require("devtools/shared/plural-form"); const Actions = require("../actions/index"); const { L10N } = require("../l10n"); +const { Prefs } = require("../prefs"); const { getDisplayedRequestsSummary, + getRequestFilterTypes, isNetworkDetailsToggleButtonDisabled, } = require("../selectors/index"); const { @@ -38,123 +41,132 @@ const TOOLBAR_CLEAR = L10N.getStr("netmonitor.toolbar.clear"); * Network monitor toolbar component * Toolbar contains a set of useful tools to control network requests */ -function Toolbar({ - clearRequests, - openStatistics, - requestFilterTypes, - setRequestFilterText, - networkDetailsToggleDisabled, - networkDetailsOpen, - summary, - toggleNetworkDetails, - toggleRequestFilterType, -}) { - let toggleButtonClassName = [ - "network-details-panel-toggle", - "devtools-button", - ]; - if (!networkDetailsOpen) { - toggleButtonClassName.push("pane-collapsed"); - } +const Toolbar = createClass({ + displayName: "Toolbar", - let { count, contentSize, transferredSize, millis } = summary; - const text = (count === 0) ? L10N.getStr("networkMenu.empty") : - PluralForm.get(count, L10N.getStr("networkMenu.summary2")) - .replace("#1", count) - .replace("#2", getSizeWithDecimals(contentSize / 1024)) - .replace("#3", getSizeWithDecimals(transferredSize / 1024)) - .replace("#4", getTimeWithDecimals(millis / 1000)); + propTypes: { + clearRequests: PropTypes.func.isRequired, + openStatistics: PropTypes.func.isRequired, + requestFilterTypes: PropTypes.array.isRequired, + setRequestFilterText: PropTypes.func.isRequired, + networkDetailsToggleDisabled: PropTypes.bool.isRequired, + networkDetailsOpen: PropTypes.bool.isRequired, + summary: PropTypes.object.isRequired, + toggleNetworkDetails: PropTypes.func.isRequired, + toggleRequestFilterType: PropTypes.func.isRequired, + }, - const buttons = requestFilterTypes.entrySeq().map(([type, checked]) => { - let classList = ["devtools-button"]; - checked && classList.push("checked"); + componentDidMount() { + Prefs.filters.forEach(this.props.toggleRequestFilterType); + }, + + toggleRequestFilterType(evt) { + if (evt.type === "keydown" && (evt.key !== "" || evt.key !== "Enter")) { + return; + } + this.props.toggleRequestFilterType(evt.target.dataset.key); + }, + + render() { + let { + clearRequests, + openStatistics, + requestFilterTypes, + setRequestFilterText, + networkDetailsToggleDisabled, + networkDetailsOpen, + summary, + toggleNetworkDetails, + } = this.props; + + let toggleButtonClassName = [ + "network-details-panel-toggle", + "devtools-button", + ]; + if (!networkDetailsOpen) { + toggleButtonClassName.push("pane-collapsed"); + } + + let { count, contentSize, transferredSize, millis } = summary; + let text = (count === 0) ? L10N.getStr("networkMenu.empty") : + PluralForm.get(count, L10N.getStr("networkMenu.summary2")) + .replace("#1", count) + .replace("#2", getSizeWithDecimals(contentSize / 1024)) + .replace("#3", getSizeWithDecimals(transferredSize / 1024)) + .replace("#4", getTimeWithDecimals(millis / 1000)); + + let buttons = requestFilterTypes.map(([type, checked]) => { + let classList = ["devtools-button"]; + checked && classList.push("checked"); + + return ( + button({ + id: `requests-menu-filter-${type}-button`, + className: classList.join(" "), + key: type, + onClick: this.toggleRequestFilterType, + onKeyDown: this.toggleRequestFilterType, + "aria-pressed": checked, + "data-key": type, + }, + L10N.getStr(`netmonitor.toolbar.filter.${type}`) + ) + ); + }); return ( - button({ - id: `requests-menu-filter-${type}-button`, - className: classList.join(" "), - key: type, - onClick: toggleRequestFilterType, - onKeyDown: toggleRequestFilterType, - "aria-pressed": checked, - "data-key": type, - }, - L10N.getStr(`netmonitor.toolbar.filter.${type}`) + span({ className: "devtools-toolbar devtools-toolbar-container" }, + span({ className: "devtools-toolbar-group" }, + button({ + id: "requests-menu-clear-button", + className: "devtools-button devtools-clear-icon", + title: TOOLBAR_CLEAR, + onClick: clearRequests, + }), + div({ id: "requests-menu-filter-buttons" }, buttons), + ), + span({ className: "devtools-toolbar-group" }, + button({ + id: "requests-menu-network-summary-button", + className: "devtools-button", + title: count ? text : L10N.getStr("netmonitor.toolbar.perf"), + onClick: openStatistics, + }, + span({ className: "summary-info-icon" }), + span({ className: "summary-info-text" }, text), + ), + SearchBox({ + delay: FILTER_SEARCH_DELAY, + keyShortcut: SEARCH_KEY_SHORTCUT, + placeholder: SEARCH_PLACE_HOLDER, + type: "filter", + onChange: setRequestFilterText, + }), + button({ + className: toggleButtonClassName.join(" "), + title: networkDetailsOpen ? COLLPASE_DETAILS_PANE : EXPAND_DETAILS_PANE, + disabled: networkDetailsToggleDisabled, + tabIndex: "0", + onClick: toggleNetworkDetails, + }), + ) ) ); - }).toArray(); - - return ( - span({ className: "devtools-toolbar devtools-toolbar-container" }, - span({ className: "devtools-toolbar-group" }, - button({ - id: "requests-menu-clear-button", - className: "devtools-button devtools-clear-icon", - title: TOOLBAR_CLEAR, - onClick: clearRequests, - }), - div({ id: "requests-menu-filter-buttons" }, buttons), - ), - span({ className: "devtools-toolbar-group" }, - button({ - id: "requests-menu-network-summary-button", - className: "devtools-button", - title: count ? text : L10N.getStr("netmonitor.toolbar.perf"), - onClick: openStatistics, - }, - span({ className: "summary-info-icon" }), - span({ className: "summary-info-text" }, text), - ), - SearchBox({ - delay: FILTER_SEARCH_DELAY, - keyShortcut: SEARCH_KEY_SHORTCUT, - placeholder: SEARCH_PLACE_HOLDER, - type: "filter", - onChange: setRequestFilterText, - }), - button({ - className: toggleButtonClassName.join(" "), - title: networkDetailsOpen ? COLLPASE_DETAILS_PANE : EXPAND_DETAILS_PANE, - disabled: networkDetailsToggleDisabled, - tabIndex: "0", - onClick: toggleNetworkDetails, - }), - ) - ) - ); -} - -Toolbar.displayName = "Toolbar"; - -Toolbar.propTypes = { - clearRequests: PropTypes.func.isRequired, - openStatistics: PropTypes.func.isRequired, - requestFilterTypes: PropTypes.object.isRequired, - setRequestFilterText: PropTypes.func.isRequired, - networkDetailsToggleDisabled: PropTypes.bool.isRequired, - networkDetailsOpen: PropTypes.bool.isRequired, - summary: PropTypes.object.isRequired, - toggleNetworkDetails: PropTypes.func.isRequired, - toggleRequestFilterType: PropTypes.func.isRequired, -}; + } +}); module.exports = connect( (state) => ({ networkDetailsToggleDisabled: isNetworkDetailsToggleButtonDisabled(state), networkDetailsOpen: state.ui.networkDetailsOpen, - requestFilterTypes: state.filters.requestFilterTypes, + requestFilterTypes: getRequestFilterTypes(state), summary: getDisplayedRequestsSummary(state), }), (dispatch) => ({ clearRequests: () => dispatch(Actions.clearRequests()), openStatistics: () => dispatch(Actions.openStatistics(true)), setRequestFilterText: (text) => dispatch(Actions.setRequestFilterText(text)), - toggleRequestFilterType: (evt) => { - if (evt.type === "keydown" && (evt.key !== "" || evt.key !== "Enter")) { - return; - } - dispatch(Actions.toggleRequestFilterType(evt.target.dataset.key)); - }, + toggleRequestFilterType: (type) => dispatch(Actions.toggleRequestFilterType(type)), toggleNetworkDetails: () => dispatch(Actions.toggleNetworkDetails()), - }) + }), )(Toolbar); diff --git a/devtools/client/netmonitor/har/test/browser_net_har_copy_all_as_har.js b/devtools/client/netmonitor/har/test/browser_net_har_copy_all_as_har.js index c062b9564fda..d51f18e7c4e1 100644 --- a/devtools/client/netmonitor/har/test/browser_net_har_copy_all_as_har.js +++ b/devtools/client/netmonitor/har/test/browser_net_har_copy_all_as_har.js @@ -14,7 +14,7 @@ add_task(function* () { let { document, gStore, windowRequire } = monitor.panelWin; let Actions = windowRequire("devtools/client/netmonitor/actions/index"); let RequestListContextMenu = windowRequire( - "devtools/client/netmonitor/components/request-list-context-menu"); + "devtools/client/netmonitor/request-list-context-menu"); gStore.dispatch(Actions.batchEnable(false)); diff --git a/devtools/client/netmonitor/har/test/browser_net_har_post_data.js b/devtools/client/netmonitor/har/test/browser_net_har_post_data.js index ac7861122fd2..207fd1964d59 100644 --- a/devtools/client/netmonitor/har/test/browser_net_har_post_data.js +++ b/devtools/client/netmonitor/har/test/browser_net_har_post_data.js @@ -15,7 +15,7 @@ add_task(function* () { let { document, gStore, windowRequire } = monitor.panelWin; let Actions = windowRequire("devtools/client/netmonitor/actions/index"); let RequestListContextMenu = windowRequire( - "devtools/client/netmonitor/components/request-list-context-menu"); + "devtools/client/netmonitor/request-list-context-menu"); gStore.dispatch(Actions.batchEnable(false)); diff --git a/devtools/client/netmonitor/har/test/browser_net_har_throttle_upload.js b/devtools/client/netmonitor/har/test/browser_net_har_throttle_upload.js index 8871c2d04174..d45bb10e215d 100644 --- a/devtools/client/netmonitor/har/test/browser_net_har_throttle_upload.js +++ b/devtools/client/netmonitor/har/test/browser_net_har_throttle_upload.js @@ -19,7 +19,7 @@ function* throttleUploadTest(actuallyThrottle) { let { document, gStore, windowRequire, NetMonitorController } = monitor.panelWin; let Actions = windowRequire("devtools/client/netmonitor/actions/index"); let RequestListContextMenu = windowRequire( - "devtools/client/netmonitor/components/request-list-context-menu"); + "devtools/client/netmonitor/request-list-context-menu"); gStore.dispatch(Actions.batchEnable(false)); diff --git a/devtools/client/netmonitor/middleware/prefs.js b/devtools/client/netmonitor/middleware/prefs.js index 3f8998074139..a67b943d43e3 100644 --- a/devtools/client/netmonitor/middleware/prefs.js +++ b/devtools/client/netmonitor/middleware/prefs.js @@ -9,7 +9,7 @@ const { TOGGLE_REQUEST_FILTER_TYPE, } = require("../constants"); const { Prefs } = require("../prefs"); -const { getActiveFilters } = require("../selectors/index"); +const { getRequestFilterTypes } = require("../selectors/index"); /** * Whenever the User clicks on a filter in the network monitor, save the new @@ -20,7 +20,9 @@ function prefsMiddleware(store) { const res = next(action); if (action.type === ENABLE_REQUEST_FILTER_TYPE_ONLY || action.type === TOGGLE_REQUEST_FILTER_TYPE) { - Prefs.filters = getActiveFilters(store.getState()); + Prefs.filters = getRequestFilterTypes(store.getState()) + .filter(([type, check]) => check) + .map(([type, check]) => type); } return res; }; diff --git a/devtools/client/netmonitor/moz.build b/devtools/client/netmonitor/moz.build index 105b692ddbcc..2d0bcfcd9499 100644 --- a/devtools/client/netmonitor/moz.build +++ b/devtools/client/netmonitor/moz.build @@ -22,6 +22,8 @@ DevToolsModules( 'netmonitor-view.js', 'panel.js', 'prefs.js', + 'request-list-context-menu.js', + 'request-list-tooltip.js', 'request-utils.js', 'sort-predicates.js', 'store.js', diff --git a/devtools/client/netmonitor/netmonitor-controller.js b/devtools/client/netmonitor/netmonitor-controller.js index 03af05e4b300..213485afc125 100644 --- a/devtools/client/netmonitor/netmonitor-controller.js +++ b/devtools/client/netmonitor/netmonitor-controller.js @@ -2,8 +2,7 @@ * 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/. */ -/* eslint-disable mozilla/reject-some-requires */ -/* globals window, NetMonitorView, gStore, gNetwork, dumpn */ +/* globals window, NetMonitorView, gStore, gNetwork */ "use strict"; @@ -386,7 +385,6 @@ TargetEventsHandler.prototype = { * Listen for events emitted by the current tab target. */ connect: function () { - dumpn("TargetEventsHandler is connecting..."); this.target.on("close", this._onTabDetached); this.target.on("navigate", this._onTabNavigated); this.target.on("will-navigate", this._onTabNavigated); @@ -399,7 +397,6 @@ TargetEventsHandler.prototype = { if (!this.target) { return; } - dumpn("TargetEventsHandler is disconnecting..."); this.target.off("close", this._onTabDetached); this.target.off("navigate", this._onTabNavigated); this.target.off("will-navigate", this._onTabNavigated); @@ -479,7 +476,6 @@ NetworkEventsHandler.prototype = { * Connect to the current target client. */ connect: function () { - dumpn("NetworkEventsHandler is connecting..."); this.webConsoleClient.on("networkEvent", this._onNetworkEvent); this.webConsoleClient.on("networkEventUpdate", this._onNetworkEventUpdate); @@ -497,7 +493,6 @@ NetworkEventsHandler.prototype = { if (!this.client) { return; } - dumpn("NetworkEventsHandler is disconnecting..."); this.webConsoleClient.off("networkEvent", this._onNetworkEvent); this.webConsoleClient.off("networkEventUpdate", this._onNetworkEventUpdate); diff --git a/devtools/client/netmonitor/netmonitor-view.js b/devtools/client/netmonitor/netmonitor-view.js index 7b18ee7ce2b6..6cec528d7210 100644 --- a/devtools/client/netmonitor/netmonitor-view.js +++ b/devtools/client/netmonitor/netmonitor-view.js @@ -2,7 +2,6 @@ * 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/. */ -/* eslint-env browser */ /* globals gStore, NetMonitorController */ "use strict"; @@ -13,10 +12,8 @@ const ReactDOM = require("devtools/client/shared/vendor/react-dom"); const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider); // Components -const NetworkDetailsPanel = createFactory(require("./shared/components/network-details-panel")); -const RequestList = createFactory(require("./components/request-list")); +const MonitorPanel = createFactory(require("./components/monitor-panel")); const StatisticsPanel = createFactory(require("./components/statistics-panel")); -const Toolbar = createFactory(require("./components/toolbar")); /** * Object defining the network monitor view components. @@ -28,18 +25,11 @@ exports.NetMonitorView = { initialize: function () { this._body = document.querySelector("#body"); - this.networkDetailsPanel = document.querySelector( - "#react-network-details-panel-hook"); + this.monitorPanel = document.querySelector("#react-monitor-panel-hook"); ReactDOM.render(Provider( { store: gStore }, - NetworkDetailsPanel({ toolbox: NetMonitorController._toolbox }), - ), this.networkDetailsPanel); - - this.requestList = document.querySelector("#react-request-list-hook"); - ReactDOM.render(Provider( - { store: gStore }, - RequestList({ toolbox: NetMonitorController._toolbox }) - ), this.requestList); + MonitorPanel(), + ), this.monitorPanel); this.statisticsPanel = document.querySelector("#react-statistics-panel-hook"); ReactDOM.render(Provider( @@ -47,12 +37,6 @@ exports.NetMonitorView = { StatisticsPanel(), ), this.statisticsPanel); - this.toolbar = document.querySelector("#react-toolbar-hook"); - ReactDOM.render(Provider( - { store: gStore }, - Toolbar(), - ), this.toolbar); - // Store watcher here is for observing the statisticsOpen state change. // It should be removed once we migrate to react and apply react/redex binding. this.unsubscribeStore = gStore.subscribe(storeWatcher( @@ -66,19 +50,17 @@ exports.NetMonitorView = { * Destroys the network monitor view. */ destroy: function () { - ReactDOM.unmountComponentAtNode(this.networkDetailsPanel); - ReactDOM.unmountComponentAtNode(this.requestList); + ReactDOM.unmountComponentAtNode(this.monitorPanel); ReactDOM.unmountComponentAtNode(this.statisticsPanel); - ReactDOM.unmountComponentAtNode(this.toolbar); this.unsubscribeStore(); }, toggleFrontendMode: function () { if (gStore.getState().ui.statisticsOpen) { - this._body.selectedPanel = document.querySelector("#react-statistics-panel-hook"); + this._body.selectedPanel = this.statisticsPanel; NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED); } else { - this._body.selectedPanel = document.querySelector("#inspector-panel"); + this._body.selectedPanel = this.monitorPanel; } }, }; diff --git a/devtools/client/netmonitor/netmonitor.js b/devtools/client/netmonitor/netmonitor.js index 5c23b5c52657..85763b21b11d 100644 --- a/devtools/client/netmonitor/netmonitor.js +++ b/devtools/client/netmonitor/netmonitor.js @@ -3,12 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* globals window, document, NetMonitorController, NetMonitorView */ -/* exported Netmonitor, NetMonitorController, NetMonitorView, $, $all, dumpn */ +/* exported Netmonitor, NetMonitorController, NetMonitorView */ "use strict"; const Cu = Components.utils; -const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); const { BrowserLoader } = Cu.import("resource://devtools/client/shared/browser-loader.js", {}); function Netmonitor(toolbox) { @@ -39,22 +38,3 @@ Netmonitor.prototype = { return window.NetMonitorController.shutdownNetMonitor(); } }; - -/** - * DOM query helper. - * TODO: Move it into "dom-utils.js" module and "require" it when needed. - */ -var $ = (selector, target = document) => target.querySelector(selector); -var $all = (selector, target = document) => target.querySelectorAll(selector); - -/** - * Helper method for debugging. - * @param string - */ -function dumpn(str) { - if (wantLogging) { - dump("NET-FRONTEND: " + str + "\n"); - } -} - -var wantLogging = Services.prefs.getBoolPref("devtools.debugger.log"); diff --git a/devtools/client/netmonitor/netmonitor.xul b/devtools/client/netmonitor/netmonitor.xul index fba438809b2c..ba2ef13a9825 100644 --- a/devtools/client/netmonitor/netmonitor.xul +++ b/devtools/client/netmonitor/netmonitor.xul @@ -18,31 +18,9 @@ class="theme-sidebar" flex="1" data-localization-bundle="devtools/client/locales/netmonitor.properties"> - - - - - - - - - - - - - - + + diff --git a/devtools/client/netmonitor/reducers/ui.js b/devtools/client/netmonitor/reducers/ui.js index ddd25b93446c..d40e47d10828 100644 --- a/devtools/client/netmonitor/reducers/ui.js +++ b/devtools/client/netmonitor/reducers/ui.js @@ -8,7 +8,9 @@ const I = require("devtools/client/shared/vendor/immutable"); const { OPEN_NETWORK_DETAILS, OPEN_STATISTICS, + REMOVE_SELECTED_CUSTOM_REQUEST, SELECT_DETAILS_PANEL_TAB, + SEND_CUSTOM_REQUEST, WATERFALL_RESIZE, } = require("../constants"); @@ -44,6 +46,9 @@ function ui(state = new UI(), action) { return openNetworkDetails(state, action); case OPEN_STATISTICS: return openStatistics(state, action); + case REMOVE_SELECTED_CUSTOM_REQUEST: + case SEND_CUSTOM_REQUEST: + return openNetworkDetails(state, { open: false }); case SELECT_DETAILS_PANEL_TAB: return setDetailsPanelTab(state, action); case WATERFALL_RESIZE: diff --git a/devtools/client/netmonitor/components/request-list-context-menu.js b/devtools/client/netmonitor/request-list-context-menu.js similarity index 99% rename from devtools/client/netmonitor/components/request-list-context-menu.js rename to devtools/client/netmonitor/request-list-context-menu.js index bdef46e22f39..6538deeb1b7d 100644 --- a/devtools/client/netmonitor/components/request-list-context-menu.js +++ b/devtools/client/netmonitor/request-list-context-menu.js @@ -12,17 +12,17 @@ const { Curl } = require("devtools/client/shared/curl"); const { gDevTools } = require("devtools/client/framework/devtools"); const Menu = require("devtools/client/framework/menu"); const MenuItem = require("devtools/client/framework/menu-item"); -const { L10N } = require("../l10n"); +const { L10N } = require("./l10n"); const { formDataURI, getFormDataSections, getUrlQuery, parseQueryString, -} = require("../request-utils"); +} = require("./request-utils"); const { getSelectedRequest, getSortedRequests, -} = require("../selectors/index"); +} = require("./selectors/index"); loader.lazyRequireGetter(this, "HarExporter", "devtools/client/netmonitor/har/har-exporter", true); diff --git a/devtools/client/netmonitor/components/request-list-tooltip.js b/devtools/client/netmonitor/request-list-tooltip.js similarity index 97% rename from devtools/client/netmonitor/components/request-list-tooltip.js rename to devtools/client/netmonitor/request-list-tooltip.js index d0d00edb9778..623b2cfaeaa1 100644 --- a/devtools/client/netmonitor/components/request-list-tooltip.js +++ b/devtools/client/netmonitor/request-list-tooltip.js @@ -11,8 +11,8 @@ const { setImageTooltip, getImageDimensions, } = require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper"); -const { WEBCONSOLE_L10N } = require("../l10n"); -const { formDataURI } = require("../request-utils"); +const { WEBCONSOLE_L10N } = require("./l10n"); +const { formDataURI } = require("./request-utils"); // px const REQUESTS_TOOLTIP_IMAGE_MAX_DIM = 400; diff --git a/devtools/client/netmonitor/selectors/filters.js b/devtools/client/netmonitor/selectors/filters.js index 4f94bc836ab7..ab07fdd63499 100644 --- a/devtools/client/netmonitor/selectors/filters.js +++ b/devtools/client/netmonitor/selectors/filters.js @@ -4,11 +4,10 @@ "use strict"; -function getActiveFilters(state) { - return state.filters.requestFilterTypes.toSeq() - .filter(checked => checked).keySeq().toArray(); +function getRequestFilterTypes(state) { + return state.filters.requestFilterTypes.entrySeq().toArray(); } module.exports = { - getActiveFilters + getRequestFilterTypes, }; diff --git a/devtools/client/netmonitor/selectors/requests.js b/devtools/client/netmonitor/selectors/requests.js index 04320cef5dcb..776a6f78146a 100644 --- a/devtools/client/netmonitor/selectors/requests.js +++ b/devtools/client/netmonitor/selectors/requests.js @@ -92,8 +92,8 @@ const getDisplayedRequestsSummary = createSelector( return { count: requests.size, contentSize: totalBytes.contentSize, - transferredSize: totalBytes.transferredSize, millis: totalMillis, + transferredSize: totalBytes.transferredSize, }; } ); diff --git a/devtools/client/netmonitor/shared/components/network-details-panel.js b/devtools/client/netmonitor/shared/components/network-details-panel.js index 197610c39cfb..0998b51b61e1 100644 --- a/devtools/client/netmonitor/shared/components/network-details-panel.js +++ b/devtools/client/netmonitor/shared/components/network-details-panel.js @@ -2,12 +2,9 @@ * 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/. */ -/* globals document */ - "use strict"; const { - createClass, createFactory, DOM, PropTypes, @@ -15,84 +12,58 @@ const { const { connect } = require("devtools/client/shared/vendor/react-redux"); const Actions = require("../../actions/index"); const { getSelectedRequest } = require("../../selectors/index"); -const { Prefs } = require("../../prefs"); // Components const CustomRequestPanel = createFactory(require("./custom-request-panel")); const TabboxPanel = createFactory(require("./tabbox-panel")); const { div } = DOM; + /* * Network details panel component */ -const NetworkDetailsPanel = createClass({ - displayName: "NetworkDetailsPanel", - - propTypes: { - activeTabId: PropTypes.string, - cloneSelectedRequest: PropTypes.func.isRequired, - open: PropTypes.bool, - request: PropTypes.object, - selectTab: PropTypes.func.isRequired, - toolbox: PropTypes.object.isRequired, - }, - - componentDidMount() { - // FIXME: Workaround should be removed in bug 1309183 - document.getElementById("splitter-adjustable-box") - .setAttribute("width", Prefs.networkDetailsWidth); - document.getElementById("splitter-adjustable-box") - .setAttribute("height", Prefs.networkDetailsHeight); - }, - - componentWillUnmount() { - // FIXME: Workaround should be removed in bug 1309183 - Prefs.networkDetailsWidth = - document.getElementById("splitter-adjustable-box").getAttribute("width"); - Prefs.networkDetailsHeight = - document.getElementById("splitter-adjustable-box").getAttribute("height"); - }, - - render() { - let { - activeTabId, - cloneSelectedRequest, - open, - request, - selectTab, - toolbox, - } = this.props; - - if (!open || !request) { - // FIXME: Workaround should be removed in bug 1309183 - document.getElementById("splitter-adjustable-box").setAttribute("hidden", true); - return null; - } - // FIXME: Workaround should be removed in bug 1309183 - document.getElementById("splitter-adjustable-box").removeAttribute("hidden"); - - return ( - div({ className: "network-details-panel" }, - !request.isCustom ? - TabboxPanel({ - activeTabId, - request, - selectTab, - toolbox, - }) : - CustomRequestPanel({ - cloneSelectedRequest, - request, - }) - ) - ); +function NetworkDetailsPanel({ + activeTabId, + cloneSelectedRequest, + request, + selectTab, + toolbox, +}) { + if (!request) { + return null; } -}); + + return ( + div({ className: "network-details-panel" }, + !request.isCustom ? + TabboxPanel({ + activeTabId, + request, + selectTab, + toolbox, + }) : + CustomRequestPanel({ + cloneSelectedRequest, + request, + }) + ) + ); +} + +NetworkDetailsPanel.displayName = "NetworkDetailsPanel"; + +NetworkDetailsPanel.propTypes = { + activeTabId: PropTypes.string, + cloneSelectedRequest: PropTypes.func.isRequired, + open: PropTypes.bool, + request: PropTypes.object, + selectTab: PropTypes.func.isRequired, + toolbox: PropTypes.object.isRequired, +}; module.exports = connect( (state) => ({ activeTabId: state.ui.detailsPanelSelectedTab, - open: state.ui.networkDetailsOpen, request: getSelectedRequest(state), }), (dispatch) => ({ diff --git a/devtools/client/netmonitor/test/browser.ini b/devtools/client/netmonitor/test/browser.ini index 9a250ceb7b1e..2732cc754ded 100644 --- a/devtools/client/netmonitor/test/browser.ini +++ b/devtools/client/netmonitor/test/browser.ini @@ -128,7 +128,6 @@ skip-if = (os == 'linux' && debug && bits == 32) # Bug 1303439 [browser_net_post-data-04.js] [browser_net_prefs-and-l10n.js] [browser_net_prefs-reload.js] -skip-if = true # bug 1309183, it should be fixed by SplitBox support [browser_net_raw_headers.js] [browser_net_reload-button.js] [browser_net_reload-markers.js] diff --git a/devtools/client/netmonitor/test/browser_net_complex-params.js b/devtools/client/netmonitor/test/browser_net_complex-params.js index 65db6a74f640..338d922d8994 100644 --- a/devtools/client/netmonitor/test/browser_net_complex-params.js +++ b/devtools/client/netmonitor/test/browser_net_complex-params.js @@ -25,42 +25,49 @@ add_task(function* () { yield wait; wait = waitForDOM(document, "#params-panel .tree-section", 2); - gStore.dispatch(Actions.selectRequestByIndex(0)); + EventUtils.sendMouseEvent({ type: "mousedown" }, + document.querySelectorAll(".request-list-item")[0]); EventUtils.sendMouseEvent({ type: "click" }, document.querySelector("#params-tab")); yield wait; testParamsTab1("a", '""', '{ "foo": "bar" }', '""'); wait = waitForDOM(document, "#params-panel .tree-section", 2); - gStore.dispatch(Actions.selectRequestByIndex(1)); + EventUtils.sendMouseEvent({ type: "mousedown" }, + document.querySelectorAll(".request-list-item")[1]); yield wait; testParamsTab1("a", '"b"', '{ "foo": "bar" }', '""'); wait = waitForDOM(document, "#params-panel .tree-section", 2); - gStore.dispatch(Actions.selectRequestByIndex(2)); + EventUtils.sendMouseEvent({ type: "mousedown" }, + document.querySelectorAll(".request-list-item")[2]); yield wait; testParamsTab1("a", '"b"', "foo", '"bar"'); wait = waitForDOM(document, "#params-panel tr:not(.tree-section).treeRow", 2); - gStore.dispatch(Actions.selectRequestByIndex(3)); + EventUtils.sendMouseEvent({ type: "mousedown" }, + document.querySelectorAll(".request-list-item")[3]); yield wait; testParamsTab2("a", '""', '{ "foo": "bar" }', "js"); wait = waitForDOM(document, "#params-panel tr:not(.tree-section).treeRow", 2); - gStore.dispatch(Actions.selectRequestByIndex(4)); + EventUtils.sendMouseEvent({ type: "mousedown" }, + document.querySelectorAll(".request-list-item")[4]); yield wait; testParamsTab2("a", '"b"', '{ "foo": "bar" }', "js"); // Wait for all tree sections and editor updated by react let waitSections = waitForDOM(document, "#params-panel .tree-section", 2); let waitEditor = waitForDOM(document, "#params-panel .editor-mount iframe"); - gStore.dispatch(Actions.selectRequestByIndex(5)); + EventUtils.sendMouseEvent({ type: "mousedown" }, + document.querySelectorAll(".request-list-item")[5]); let [, editorFrames] = yield Promise.all([waitSections, waitEditor]); yield once(editorFrames[0], "DOMContentLoaded"); yield waitForDOM(editorFrames[0].contentDocument, ".CodeMirror-code"); testParamsTab2("a", '"b"', "?foo=bar", "text"); - gStore.dispatch(Actions.selectRequestByIndex(6)); + EventUtils.sendMouseEvent({ type: "mousedown" }, + document.querySelectorAll(".request-list-item")[6]); testParamsTab3(); yield teardown(monitor); diff --git a/devtools/client/netmonitor/test/browser_net_prefs-reload.js b/devtools/client/netmonitor/test/browser_net_prefs-reload.js index a5c457cb4c97..d63801f27dec 100644 --- a/devtools/client/netmonitor/test/browser_net_prefs-reload.js +++ b/devtools/client/netmonitor/test/browser_net_prefs-reload.js @@ -8,11 +8,10 @@ */ add_task(function* () { - let Actions = require("devtools/client/netmonitor/actions/index"); - let { getActiveFilters } = require("devtools/client/netmonitor/selectors/index"); - let { monitor } = yield initNetMonitor(SIMPLE_URL); - let { document, gStore, Prefs } = monitor.panelWin; + let { getRequestFilterTypes } = monitor.panelWin + .windowRequire("devtools/client/netmonitor/selectors/index"); + let Actions = monitor.panelWin.windowRequire("devtools/client/netmonitor/actions/index"); info("Starting test... "); // This test reopens the network monitor a bunch of times, for different @@ -22,7 +21,9 @@ add_task(function* () { // Use these getters instead of caching instances inside the panel win, // since the tool is reopened a bunch of times during this test // and the instances will differ. - let getStore = () => gStore; + let getDoc = () => monitor.panelWin.document; + let getPrefs = () => monitor.panelWin.windowRequire("devtools/client/netmonitor/prefs").Prefs; + let getStore = () => monitor.panelWin.gStore; let getState = () => getStore().getState(); let prefsToCheck = { @@ -31,7 +32,9 @@ add_task(function* () { newValue: ["html", "css"], // Getter used to retrieve the current value from the frontend, in order // to verify that the pref was applied properly. - validateValue: () => getActiveFilters(getState()), + validateValue: () => getRequestFilterTypes(getState()) + .filter(([type, check]) => check) + .map(([type, check]) => type), // Predicate used to modify the frontend when setting the new pref value, // before trying to validate the changes. modifyFrontend: (value) => value.forEach(e => @@ -40,16 +43,16 @@ add_task(function* () { networkDetailsWidth: { newValue: ~~(Math.random() * 200 + 100), validateValue: () => - ~~document.querySelector(".network-details-panel").getAttribute("width"), + getDoc().querySelector(".monitor-panel .split-box .controlled").clientWidth, modifyFrontend: (value) => - document.querySelector(".network-details-panel").setAttribute("width", value) + getDoc().querySelector(".monitor-panel .split-box .controlled").style.width = `${value}px`, }, networkDetailsHeight: { newValue: ~~(Math.random() * 300 + 100), validateValue: () => - ~~document.querySelector(".network-details-panel").getAttribute("height"), + getDoc().querySelector(".monitor-panel .split-box .controlled").clientHeight, modifyFrontend: (value) => - document.querySelector(".network-details-panel").setAttribute("height", value) + getDoc().querySelector(".monitor-panel .split-box .controlled").style.height = `${value}px` } /* add more prefs here... */ }; @@ -66,31 +69,41 @@ add_task(function* () { info("Caching initial pref values."); for (let name in prefsToCheck) { - let currentValue = Prefs[name]; + let currentValue = getPrefs()[name]; prefsToCheck[name].firstValue = currentValue; } } - function validateFirstPrefValues() { + function validateFirstPrefValues(isVerticalSplitter) { info("Validating current pref values to the UI elements."); for (let name in prefsToCheck) { - let currentValue = Prefs[name]; + if ((isVerticalSplitter && name === "networkDetailsHeight") || + (!isVerticalSplitter && name === "networkDetailsWidth")) { + continue + } + + let currentValue = getPrefs()[name]; let firstValue = prefsToCheck[name].firstValue; let validateValue = prefsToCheck[name].validateValue; - is(currentValue.toSource(), firstValue.toSource(), - "Pref " + name + " should be equal to first value: " + firstValue); - is(currentValue.toSource(), validateValue().toSource(), + is(firstValue.toSource(), currentValue.toSource(), + "Pref " + name + " should be equal to first value: " + currentValue); + is(validateValue().toSource(), currentValue.toSource(), "Pref " + name + " should validate: " + currentValue); } } - function modifyFrontend() { + function modifyFrontend(isVerticalSplitter) { info("Modifying UI elements to the specified new values."); for (let name in prefsToCheck) { - let currentValue = Prefs[name]; + if ((isVerticalSplitter && name === "networkDetailsHeight") || + (!isVerticalSplitter && name === "networkDetailsWidth")) { + continue + } + + let currentValue = getPrefs()[name]; let firstValue = prefsToCheck[name].firstValue; let newValue = prefsToCheck[name].newValue; let validateValue = prefsToCheck[name].validateValue; @@ -99,38 +112,48 @@ add_task(function* () { modFrontend(newValue); info("Modified UI element affecting " + name + " to: " + newValue); - is(currentValue.toSource(), firstValue.toSource(), - "Pref " + name + " should still be equal to first value: " + firstValue); - isnot(currentValue.toSource(), newValue.toSource(), - "Pref " + name + " should't yet be equal to second value: " + newValue); - is(newValue.toSource(), validateValue().toSource(), + is(firstValue.toSource(), currentValue.toSource(), + "Pref " + name + " should still be equal to first value: " + currentValue); + isnot(newValue.toSource(), currentValue.toSource(), + "Pref " + name + " should't yet be equal to second value: " + currentValue); + is(validateValue().toSource(), newValue.toSource(), "The UI element affecting " + name + " should validate: " + newValue); } } - function validateNewPrefValues() { + function validateNewPrefValues(isVerticalSplitter) { info("Invalidating old pref values to the modified UI elements."); for (let name in prefsToCheck) { - let currentValue = Prefs[name]; + if ((isVerticalSplitter && name === "networkDetailsHeight") || + (!isVerticalSplitter && name === "networkDetailsWidth")) { + continue + } + + let currentValue = getPrefs()[name]; let firstValue = prefsToCheck[name].firstValue; let newValue = prefsToCheck[name].newValue; let validateValue = prefsToCheck[name].validateValue; - isnot(currentValue.toSource(), firstValue.toSource(), - "Pref " + name + " should't be equal to first value: " + firstValue); - is(currentValue.toSource(), newValue.toSource(), - "Pref " + name + " should now be equal to second value: " + newValue); - is(newValue.toSource(), validateValue().toSource(), + isnot(firstValue.toSource(), currentValue.toSource(), + "Pref " + name + " should't be equal to first value: " + currentValue); + is(newValue.toSource(), currentValue.toSource(), + "Pref " + name + " should now be equal to second value: " + currentValue); + is(validateValue().toSource(), newValue.toSource(), "The UI element affecting " + name + " should validate: " + newValue); } } - function resetFrontend() { + function resetFrontend(isVerticalSplitter) { info("Resetting UI elements to the cached initial pref values."); for (let name in prefsToCheck) { - let currentValue = Prefs[name]; + if ((isVerticalSplitter && name === "networkDetailsHeight") || + (!isVerticalSplitter && name === "networkDetailsWidth")) { + continue + } + + let currentValue = getPrefs()[name]; let firstValue = prefsToCheck[name].firstValue; let newValue = prefsToCheck[name].newValue; let validateValue = prefsToCheck[name].validateValue; @@ -139,38 +162,54 @@ add_task(function* () { modFrontend(firstValue); info("Modified UI element affecting " + name + " to: " + firstValue); - isnot(currentValue.toSource(), firstValue.toSource(), - "Pref " + name + " should't yet be equal to first value: " + firstValue); - is(currentValue.toSource(), newValue.toSource(), - "Pref " + name + " should still be equal to second value: " + newValue); - is(firstValue.toSource(), validateValue().toSource(), + isnot(firstValue.toSource(), currentValue.toSource(), + "Pref " + name + " should't yet be equal to first value: " + currentValue); + is(newValue.toSource(), currentValue.toSource(), + "Pref " + name + " should still be equal to second value: " + currentValue); + is(validateValue().toSource(), firstValue.toSource(), "The UI element affecting " + name + " should validate: " + firstValue); } } + function* restartNetMonitorAndSetupEnv() { + let newMonitor = yield restartNetMonitor(monitor); + monitor = newMonitor.monitor; + + let networkEvent = waitForNetworkEvents(monitor, 1); + newMonitor.tab.linkedBrowser.reload(); + yield networkEvent; + + let wait = waitForDOM(getDoc(), ".network-details-panel"); + EventUtils.sendMouseEvent({ type: "click" }, + getDoc().querySelector(".network-details-panel-toggle")); + yield wait; + } + function* testBottom() { + yield restartNetMonitorAndSetupEnv(); + info("Testing prefs reload for a bottom host."); storeFirstPrefValues(); // Validate and modify while toolbox is on the bottom. - validateFirstPrefValues(); - modifyFrontend(); + validateFirstPrefValues(true); + modifyFrontend(true); - let newMonitor = yield restartNetMonitor(monitor); - monitor = newMonitor.monitor; + yield restartNetMonitorAndSetupEnv(); // Revalidate and reset frontend while toolbox is on the bottom. - validateNewPrefValues(); - resetFrontend(); + validateNewPrefValues(true); + resetFrontend(true); - newMonitor = yield restartNetMonitor(monitor); - monitor = newMonitor.monitor; + yield restartNetMonitorAndSetupEnv(); // Revalidate. - validateFirstPrefValues(); + validateFirstPrefValues(true); } function* testSide() { + yield restartNetMonitorAndSetupEnv(); + info("Moving toolbox to the side..."); yield monitor._toolbox.switchHost(Toolbox.HostType.SIDE); @@ -178,24 +217,24 @@ add_task(function* () { storeFirstPrefValues(); // Validate and modify frontend while toolbox is on the side. - validateFirstPrefValues(); - modifyFrontend(); + validateFirstPrefValues(false); + modifyFrontend(false); - let newMonitor = yield restartNetMonitor(monitor); - monitor = newMonitor.monitor; + yield restartNetMonitorAndSetupEnv(); // Revalidate and reset frontend while toolbox is on the side. - validateNewPrefValues(); - resetFrontend(); + validateNewPrefValues(false); + resetFrontend(false); - newMonitor = yield restartNetMonitor(monitor); - monitor = newMonitor.monitor; + yield restartNetMonitorAndSetupEnv(); // Revalidate. - validateFirstPrefValues(); + validateFirstPrefValues(false); } function* testWindow() { + yield restartNetMonitorAndSetupEnv(); + info("Moving toolbox into a window..."); yield monitor._toolbox.switchHost(Toolbox.HostType.WINDOW); @@ -203,20 +242,18 @@ add_task(function* () { storeFirstPrefValues(); // Validate and modify frontend while toolbox is in a window. - validateFirstPrefValues(); - modifyFrontend(); + validateFirstPrefValues(true); + modifyFrontend(true); - let newMonitor = yield restartNetMonitor(monitor); - monitor = newMonitor.monitor; + yield restartNetMonitorAndSetupEnv(); // Revalidate and reset frontend while toolbox is in a window. - validateNewPrefValues(); - resetFrontend(); + validateNewPrefValues(true); + resetFrontend(true); - newMonitor = yield restartNetMonitor(monitor); - monitor = newMonitor.monitor; + yield restartNetMonitorAndSetupEnv(); // Revalidate. - validateFirstPrefValues(); + validateFirstPrefValues(true); } }); diff --git a/devtools/client/netmonitor/test/browser_net_statistics-01.js b/devtools/client/netmonitor/test/browser_net_statistics-01.js index 30279d79652e..ad8a9310a236 100644 --- a/devtools/client/netmonitor/test/browser_net_statistics-01.js +++ b/devtools/client/netmonitor/test/browser_net_statistics-01.js @@ -17,7 +17,7 @@ add_task(function* () { let body = document.querySelector("#body"); - is(body.selectedPanel.id, "inspector-panel", + is(body.selectedPanel.id, "react-monitor-panel-hook", "The current main panel is correct."); info("Displaying statistics view"); diff --git a/devtools/client/netmonitor/test/browser_net_statistics-02.js b/devtools/client/netmonitor/test/browser_net_statistics-02.js index c5a0a2e057bb..953e6d8905ca 100644 --- a/devtools/client/netmonitor/test/browser_net_statistics-02.js +++ b/devtools/client/netmonitor/test/browser_net_statistics-02.js @@ -43,7 +43,7 @@ add_task(function* () { EventUtils.sendMouseEvent({ type: "click" }, document.querySelector(".pie-chart-slice")); - is(body.selectedPanel.id, "inspector-panel", + is(body.selectedPanel.id, "react-monitor-panel-hook", "The main panel is switched back to the inspector panel."); testFilterButtons(monitor, "html"); diff --git a/devtools/client/shared/components/splitter/split-box.js b/devtools/client/shared/components/splitter/split-box.js index 627bf12326db..b28837874f41 100644 --- a/devtools/client/shared/components/splitter/split-box.js +++ b/devtools/client/shared/components/splitter/split-box.js @@ -20,23 +20,23 @@ const SplitBox = React.createClass({ // Custom class name. You can use more names separated by a space. className: PropTypes.string, // Initial size of controlled panel. - initialSize: PropTypes.number, + initialSize: PropTypes.string, // Initial width of controlled panel. - initialWidth: PropTypes.number, + initialWidth: PropTypes.string, // Initial height of controlled panel. - initialHeight: PropTypes.number, + initialHeight: PropTypes.string, // Left/top panel startPanel: PropTypes.any, // Min panel size. - minSize: PropTypes.number, + minSize: PropTypes.string, // Max panel size. - maxSize: PropTypes.number, + maxSize: PropTypes.string, // Right/bottom panel endPanel: PropTypes.any, // True if the right/bottom panel should be controlled. endPanelControl: PropTypes.bool, // Size of the splitter handle bar. - splitterSize: PropTypes.number, + splitterSize: PropTypes.string, // True if the splitter bar is vertical (default is vertical). vert: PropTypes.bool, // Style object. @@ -64,6 +64,14 @@ const SplitBox = React.createClass({ }; }, + componentWillReceiveProps(nextProps) { + let { vert } = nextProps; + + if (vert !== this.props.vert) { + this.setState({ vert }); + } + }, + // Dragging Events /** diff --git a/devtools/client/shared/components/tabs/tabbar.js b/devtools/client/shared/components/tabs/tabbar.js index 8995ef6d9b79..cd3193bf3659 100644 --- a/devtools/client/shared/components/tabs/tabbar.js +++ b/devtools/client/shared/components/tabs/tabbar.js @@ -22,7 +22,7 @@ let Tabbar = createClass({ displayName: "Tabbar", propTypes: { - children: PropTypes.object, + children: PropTypes.array, onSelect: PropTypes.func, showAllTabsMenu: PropTypes.bool, activeTabId: PropTypes.string, diff --git a/devtools/client/themes/netmonitor.css b/devtools/client/themes/netmonitor.css index 78d7ff893557..b6ea42711c6d 100644 --- a/devtools/client/themes/netmonitor.css +++ b/devtools/client/themes/netmonitor.css @@ -2,6 +2,7 @@ * 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/splitter/split-box.css"; @import "resource://devtools/client/shared/components/tree/tree-view.css"; @import "resource://devtools/client/shared/components/tabs/tabs.css"; @import "resource://devtools/client/shared/components/tabs/tabbar.css"; @@ -85,6 +86,8 @@ .request-list-container { display: flex; flex-direction: column; + width: 100%; + height: 100%; } .request-list-empty-notice { @@ -757,10 +760,9 @@ /* Custom request view */ .custom-request-panel { + height: 100%; overflow: auto; - /* Full view hight - toolbar height */ - height: calc(100vh - 24px); - padding: 6px 4px; + padding: 0 4px; background-color: var(--theme-sidebar-background); } @@ -1002,15 +1004,6 @@ padding-left: 8px; } - .custom-request-panel { - height: auto; - } - - #details-pane { - margin: 0 !important; - /* To prevent all the margin hacks to hide the sidebar. */ - } - .requests-menu-status { max-width: none; width: 10vw; @@ -1262,41 +1255,18 @@ height: 100%; } +.monitor-panel { + width: 100vw; + /* Devtools panel height - devtools toolbar height */ + height: calc(100vh - 24px); +} + .network-details-panel { - height: 100%; -} - -/* - * FIXME: normal html block element cannot fill outer XUL element - * This workaround should be removed after netmonitor is migrated to react - */ -#network-table { - display: -moz-box; - -moz-box-orient: vertical; - -moz-box-flex: 1; - overflow: hidden; -} - -#react-network-details-panel-hook, -#react-statistics-panel-hook, -#splitter-adjustable-box { - display: flex; - flex-direction: column; - min-width: 50px; + width: 100%; height: 100%; overflow: hidden; } -#splitter-adjustable-box[hidden=true] { - display: none; -} - -#react-request-list-hook { - -moz-box-flex: 1; -} - -#primed-cache-chart, -#empty-cache-chart { - display: -moz-box; - -moz-box-flex: 1; +.split-box { + width: 100vw; }