From 9e952ef90e72befdc159bc25c958258cb09cd98d Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 2 Dec 2016 11:14:57 -0800 Subject: [PATCH] Backed out 3 changesets (bug 1309866) for too many intermittent test failures after landing a=backout Backed out changeset 30baf39ed89f (bug 1309866) Backed out changeset e0e09f7f22a3 (bug 1309866) Backed out changeset 75d37553b7cd (bug 1309866) --- devtools/client/jar.mn | 3 +- .../client/netmonitor/actions/batching.js | 42 - devtools/client/netmonitor/actions/filters.js | 6 +- devtools/client/netmonitor/actions/index.js | 14 +- devtools/client/netmonitor/actions/moz.build | 4 - .../client/netmonitor/actions/requests.js | 56 +- .../client/netmonitor/actions/selection.js | 67 - devtools/client/netmonitor/actions/sort.js | 18 - .../netmonitor/actions/timing-markers.js | 19 - devtools/client/netmonitor/actions/ui.js | 13 +- .../netmonitor/components/clear-button.js | 17 +- .../client/netmonitor/components/moz.build | 6 - .../components/request-list-content.js | 255 --- .../components/request-list-empty.js | 65 - .../components/request-list-header.js | 197 -- .../components/request-list-item.js | 346 ---- .../components/request-list-tooltip.js | 107 -- .../netmonitor/components/request-list.js | 34 - .../netmonitor/components/summary-button.js | 12 +- .../netmonitor/components/toggle-button.js | 28 +- devtools/client/netmonitor/constants.js | 34 +- .../client/netmonitor/custom-request-view.js | 33 +- devtools/client/netmonitor/details-view.js | 10 +- devtools/client/netmonitor/har/har-builder.js | 4 +- .../client/netmonitor/har/har-collector.js | 4 +- .../test/browser_net_har_throttle_upload.js | 4 +- .../client/netmonitor/middleware/batching.js | 132 -- .../client/netmonitor/middleware/moz.build | 7 - devtools/client/netmonitor/moz.build | 7 +- .../netmonitor/netmonitor-controller.js | 131 +- devtools/client/netmonitor/netmonitor-view.js | 79 +- devtools/client/netmonitor/netmonitor.js | 60 - devtools/client/netmonitor/netmonitor.xul | 189 +- devtools/client/netmonitor/panel.js | 10 +- .../netmonitor/performance-statistics-view.js | 18 +- devtools/client/netmonitor/prefs.js | 1 + .../client/netmonitor/reducers/batching.js | 25 - .../client/netmonitor/reducers/filters.js | 4 +- devtools/client/netmonitor/reducers/index.js | 19 +- devtools/client/netmonitor/reducers/moz.build | 3 - .../client/netmonitor/reducers/requests.js | 235 +-- devtools/client/netmonitor/reducers/sort.js | 33 - .../netmonitor/reducers/timing-markers.js | 54 - devtools/client/netmonitor/reducers/ui.js | 22 +- .../netmonitor/request-list-context-menu.js | 54 +- devtools/client/netmonitor/request-utils.js | 36 +- .../client/netmonitor/requests-menu-view.js | 1675 ++++++++++++++--- .../client/netmonitor/selectors/filters.js | 13 - devtools/client/netmonitor/selectors/index.js | 62 +- .../client/netmonitor/selectors/moz.build | 5 +- .../client/netmonitor/selectors/requests.js | 119 -- devtools/client/netmonitor/selectors/ui.js | 32 - devtools/client/netmonitor/sidebar-view.js | 4 +- devtools/client/netmonitor/sort-predicates.js | 5 +- devtools/client/netmonitor/store.js | 14 +- devtools/client/netmonitor/test/browser.ini | 5 +- .../test/browser_net_accessibility-01.js | 39 +- .../test/browser_net_accessibility-02.js | 4 +- .../netmonitor/test/browser_net_api-calls.js | 2 +- .../netmonitor/test/browser_net_autoscroll.js | 36 +- .../netmonitor/test/browser_net_brotli.js | 2 +- .../test/browser_net_cached-status.js | 3 +- .../netmonitor/test/browser_net_cause.js | 10 +- .../test/browser_net_cause_redirect.js | 6 +- .../test/browser_net_content-type.js | 14 +- .../test/browser_net_copy_headers.js | 2 +- .../netmonitor/test/browser_net_copy_url.js | 2 +- .../test/browser_net_cors_requests.js | 3 +- .../netmonitor/test/browser_net_curl-utils.js | 8 +- .../test/browser_net_cyrillic-01.js | 2 +- .../test/browser_net_cyrillic-02.js | 2 +- .../netmonitor/test/browser_net_filter-01.js | 193 +- .../netmonitor/test/browser_net_filter-02.js | 210 +-- .../netmonitor/test/browser_net_filter-03.js | 78 +- .../test/browser_net_footer-summary.js | 36 +- .../netmonitor/test/browser_net_frame.js | 11 +- .../test/browser_net_icon-preview.js | 8 +- .../test/browser_net_image-tooltip.js | 18 +- .../netmonitor/test/browser_net_json-long.js | 2 +- .../test/browser_net_json-malformed.js | 2 +- .../test/browser_net_json_custom_mime.js | 2 +- .../test/browser_net_json_text_mime.js | 2 +- .../netmonitor/test/browser_net_jsonp.js | 4 +- .../test/browser_net_large-response.js | 2 +- .../netmonitor/test/browser_net_page-nav.js | 6 +- .../test/browser_net_post-data-01.js | 4 +- .../test/browser_net_prefs-reload.js | 6 +- .../test/browser_net_raw_headers.js | 6 +- .../test/browser_net_reload-button.js | 6 +- .../test/browser_net_reload-markers.js | 4 +- .../test/browser_net_req-resp-bodies.js | 2 +- .../netmonitor/test/browser_net_resend.js | 26 +- .../test/browser_net_resend_cors.js | 8 +- .../test/browser_net_resend_headers.js | 12 +- .../test/browser_net_security-icon-click.js | 10 +- .../test/browser_net_security-redirect.js | 10 +- .../test/browser_net_security-state.js | 5 +- .../browser_net_security-tab-visibility.js | 4 +- .../test/browser_net_send-beacon-other-tab.js | 4 +- .../test/browser_net_send-beacon.js | 6 +- .../test/browser_net_service-worker-status.js | 5 +- .../test/browser_net_simple-init.js | 32 +- .../test/browser_net_simple-request-data.js | 195 +- .../browser_net_simple-request-details.js | 2 +- .../test/browser_net_simple-request.js | 8 +- .../netmonitor/test/browser_net_sort-01.js | 23 +- .../netmonitor/test/browser_net_sort-02.js | 41 +- .../netmonitor/test/browser_net_sort-03.js | 38 +- .../test/browser_net_statistics-03.js | 2 +- .../test/browser_net_status-codes.js | 8 +- .../test/browser_net_streaming-response.js | 2 +- .../netmonitor/test/browser_net_throttle.js | 4 +- .../test/browser_net_timeline_ticks.js | 29 +- .../test/browser_net_timing-division.js | 27 +- devtools/client/netmonitor/test/head.js | 85 +- .../client/netmonitor/utils/format-utils.js | 44 - devtools/client/netmonitor/utils/moz.build | 8 - .../client/netmonitor/waterfall-background.js | 135 -- devtools/client/preferences/devtools.js | 1 + devtools/client/shared/browser-loader.js | 22 +- .../browser_styleeditor_fetch-from-cache.js | 15 +- devtools/client/themes/netmonitor.css | 229 +-- devtools/client/themes/toolbars.css | 1 + ...ser_netmonitor_shows_reqs_in_webconsole.js | 4 +- .../browser_webconsole_netlogging_panel.js | 4 +- ...wser_webconsole_netlogging_reset_filter.js | 8 +- ...ser_webconsole_shows_reqs_in_netmonitor.js | 4 +- 127 files changed, 2768 insertions(+), 3481 deletions(-) delete mode 100644 devtools/client/netmonitor/actions/batching.js delete mode 100644 devtools/client/netmonitor/actions/selection.js delete mode 100644 devtools/client/netmonitor/actions/sort.js delete mode 100644 devtools/client/netmonitor/actions/timing-markers.js delete mode 100644 devtools/client/netmonitor/components/request-list-content.js delete mode 100644 devtools/client/netmonitor/components/request-list-empty.js delete mode 100644 devtools/client/netmonitor/components/request-list-header.js delete mode 100644 devtools/client/netmonitor/components/request-list-item.js delete mode 100644 devtools/client/netmonitor/components/request-list-tooltip.js delete mode 100644 devtools/client/netmonitor/components/request-list.js delete mode 100644 devtools/client/netmonitor/middleware/batching.js delete mode 100644 devtools/client/netmonitor/middleware/moz.build delete mode 100644 devtools/client/netmonitor/netmonitor.js delete mode 100644 devtools/client/netmonitor/reducers/batching.js delete mode 100644 devtools/client/netmonitor/reducers/sort.js delete mode 100644 devtools/client/netmonitor/reducers/timing-markers.js delete mode 100644 devtools/client/netmonitor/selectors/filters.js delete mode 100644 devtools/client/netmonitor/selectors/requests.js delete mode 100644 devtools/client/netmonitor/selectors/ui.js delete mode 100644 devtools/client/netmonitor/utils/format-utils.js delete mode 100644 devtools/client/netmonitor/utils/moz.build delete mode 100644 devtools/client/netmonitor/waterfall-background.js diff --git a/devtools/client/jar.mn b/devtools/client/jar.mn index 6fb6ce096f79..bf39c549e552 100644 --- a/devtools/client/jar.mn +++ b/devtools/client/jar.mn @@ -14,7 +14,8 @@ devtools.jar: content/projecteditor/chrome/content/projecteditor-test.xul (projecteditor/chrome/content/projecteditor-test.xul) content/projecteditor/chrome/content/projecteditor-loader.js (projecteditor/chrome/content/projecteditor-loader.js) content/netmonitor/netmonitor.xul (netmonitor/netmonitor.xul) - content/netmonitor/netmonitor.js (netmonitor/netmonitor.js) + content/netmonitor/netmonitor-controller.js (netmonitor/netmonitor-controller.js) + content/netmonitor/netmonitor-view.js (netmonitor/netmonitor-view.js) content/webconsole/webconsole.xul (webconsole/webconsole.xul) * content/scratchpad/scratchpad.xul (scratchpad/scratchpad.xul) content/scratchpad/scratchpad.js (scratchpad/scratchpad.js) diff --git a/devtools/client/netmonitor/actions/batching.js b/devtools/client/netmonitor/actions/batching.js deleted file mode 100644 index fd68db185a32..000000000000 --- a/devtools/client/netmonitor/actions/batching.js +++ /dev/null @@ -1,42 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const { - BATCH_ACTIONS, - BATCH_ENABLE, - BATCH_RESET, -} = require("../constants"); - -/** - * Process multiple actions at once as part of one dispatch, and produce only one - * state update at the end. This action is not processed by any reducer, but by a - * special store enhancer. - */ -function batchActions(actions) { - return { - type: BATCH_ACTIONS, - actions - }; -} - -function batchEnable(enabled) { - return { - type: BATCH_ENABLE, - enabled - }; -} - -function batchReset() { - return { - type: BATCH_RESET, - }; -} - -module.exports = { - batchActions, - batchEnable, - batchReset, -}; diff --git a/devtools/client/netmonitor/actions/filters.js b/devtools/client/netmonitor/actions/filters.js index b8d8726afd39..0082c64dfdd9 100644 --- a/devtools/client/netmonitor/actions/filters.js +++ b/devtools/client/netmonitor/actions/filters.js @@ -42,12 +42,12 @@ function enableFilterTypeOnly(filter) { /** * Set filter text. * - * @param {string} text - A filter text is going to be set + * @param {string} url - A filter text is going to be set */ -function setFilterText(text) { +function setFilterText(url) { return { type: SET_FILTER_TEXT, - text, + url, }; } diff --git a/devtools/client/netmonitor/actions/index.js b/devtools/client/netmonitor/actions/index.js index 110f73ce76d8..29ce28fd5d50 100644 --- a/devtools/client/netmonitor/actions/index.js +++ b/devtools/client/netmonitor/actions/index.js @@ -4,20 +4,8 @@ "use strict"; -const batching = require("./batching"); const filters = require("./filters"); const requests = require("./requests"); -const selection = require("./selection"); -const sort = require("./sort"); -const timingMarkers = require("./timing-markers"); const ui = require("./ui"); -Object.assign(exports, - batching, - filters, - requests, - selection, - sort, - timingMarkers, - ui -); +module.exports = Object.assign({}, filters, requests, ui); diff --git a/devtools/client/netmonitor/actions/moz.build b/devtools/client/netmonitor/actions/moz.build index e81d2714edfa..9082b8bd1b88 100644 --- a/devtools/client/netmonitor/actions/moz.build +++ b/devtools/client/netmonitor/actions/moz.build @@ -3,12 +3,8 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. DevToolsModules( - 'batching.js', 'filters.js', 'index.js', 'requests.js', - 'selection.js', - 'sort.js', - 'timing-markers.js', 'ui.js', ) diff --git a/devtools/client/netmonitor/actions/requests.js b/devtools/client/netmonitor/actions/requests.js index 77871a0ff293..ae794a437496 100644 --- a/devtools/client/netmonitor/actions/requests.js +++ b/devtools/client/netmonitor/actions/requests.js @@ -5,61 +5,21 @@ "use strict"; const { - ADD_REQUEST, - UPDATE_REQUEST, - CLONE_SELECTED_REQUEST, - REMOVE_SELECTED_CUSTOM_REQUEST, - CLEAR_REQUESTS, + UPDATE_REQUESTS, } = require("../constants"); -function addRequest(id, data, batch) { - return { - type: ADD_REQUEST, - id, - data, - meta: { batch }, - }; -} - -function updateRequest(id, data, batch) { - return { - type: UPDATE_REQUEST, - id, - data, - meta: { batch }, - }; -} - /** - * Clone the currently selected request, set the "isCustom" attribute. - * Used by the "Edit and Resend" feature. + * Update request items + * + * @param {array} requests - visible request items */ -function cloneSelectedRequest() { +function updateRequests(items) { return { - type: CLONE_SELECTED_REQUEST - }; -} - -/** - * Remove a request from the list. Supports removing only cloned requests with a - * "isCustom" attribute. Other requests never need to be removed. - */ -function removeSelectedCustomRequest() { - return { - type: REMOVE_SELECTED_CUSTOM_REQUEST - }; -} - -function clearRequests() { - return { - type: CLEAR_REQUESTS + type: UPDATE_REQUESTS, + items, }; } module.exports = { - addRequest, - updateRequest, - cloneSelectedRequest, - removeSelectedCustomRequest, - clearRequests, + updateRequests, }; diff --git a/devtools/client/netmonitor/actions/selection.js b/devtools/client/netmonitor/actions/selection.js deleted file mode 100644 index dffc6d8cc000..000000000000 --- a/devtools/client/netmonitor/actions/selection.js +++ /dev/null @@ -1,67 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const { getDisplayedRequests } = require("../selectors/index"); -const { SELECT_REQUEST, PRESELECT_REQUEST } = require("../constants"); - -/** - * When a new request with a given id is added in future, select it immediately. - * Used by the "Edit and Resend" feature, where we know in advance the ID of the - * request, at a time when it wasn't sent yet. - */ -function preselectRequest(id) { - return { - type: PRESELECT_REQUEST, - id - }; -} - -/** - * Select request with a given id. - */ -function selectRequest(id) { - return { - type: SELECT_REQUEST, - id - }; -} - -const PAGE_SIZE_ITEM_COUNT_RATIO = 5; - -/** - * Move the selection up to down according to the "delta" parameter. Possible values: - * - Number: positive or negative, move up or down by specified distance - * - "PAGE_UP" | "PAGE_DOWN" (String): page up or page down - * - +Infinity | -Infinity: move to the start or end of the list - */ -function selectDelta(delta) { - return (dispatch, getState) => { - const state = getState(); - const requests = getDisplayedRequests(state); - - if (requests.isEmpty()) { - return; - } - - const selIndex = requests.findIndex(r => r.id === state.requests.selectedId); - - if (delta === "PAGE_DOWN") { - delta = Math.ceil(requests.size / PAGE_SIZE_ITEM_COUNT_RATIO); - } else if (delta === "PAGE_UP") { - delta = -Math.ceil(requests.size / PAGE_SIZE_ITEM_COUNT_RATIO); - } - - const newIndex = Math.min(Math.max(0, selIndex + delta), requests.size - 1); - const newItem = requests.get(newIndex); - dispatch(selectRequest(newItem.id)); - }; -} - -module.exports = { - preselectRequest, - selectRequest, - selectDelta, -}; diff --git a/devtools/client/netmonitor/actions/sort.js b/devtools/client/netmonitor/actions/sort.js deleted file mode 100644 index 2dd02373ec50..000000000000 --- a/devtools/client/netmonitor/actions/sort.js +++ /dev/null @@ -1,18 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const { SORT_BY } = require("../constants"); - -function sortBy(sortType) { - return { - type: SORT_BY, - sortType - }; -} - -module.exports = { - sortBy -}; diff --git a/devtools/client/netmonitor/actions/timing-markers.js b/devtools/client/netmonitor/actions/timing-markers.js deleted file mode 100644 index 4f1363a70637..000000000000 --- a/devtools/client/netmonitor/actions/timing-markers.js +++ /dev/null @@ -1,19 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -const { ADD_TIMING_MARKER, CLEAR_TIMING_MARKERS } = require("../constants"); - -exports.addTimingMarker = (marker) => { - return { - type: ADD_TIMING_MARKER, - marker - }; -}; - -exports.clearTimingMarkers = () => { - return { - type: CLEAR_TIMING_MARKERS - }; -}; diff --git a/devtools/client/netmonitor/actions/ui.js b/devtools/client/netmonitor/actions/ui.js index 31539518fb72..554921bc2781 100644 --- a/devtools/client/netmonitor/actions/ui.js +++ b/devtools/client/netmonitor/actions/ui.js @@ -6,7 +6,7 @@ const { OPEN_SIDEBAR, - WATERFALL_RESIZE, + TOGGLE_SIDEBAR, } = require("../constants"); /** @@ -25,21 +25,12 @@ function openSidebar(open) { * Toggle sidebar open state. */ function toggleSidebar() { - return (dispatch, getState) => dispatch(openSidebar(!getState().ui.sidebarOpen)); -} - -/** - * Waterfall width has changed (likely on window resize). Update the UI. - */ -function resizeWaterfall(width) { return { - type: WATERFALL_RESIZE, - width + type: TOGGLE_SIDEBAR, }; } module.exports = { openSidebar, toggleSidebar, - resizeWaterfall, }; diff --git a/devtools/client/netmonitor/components/clear-button.js b/devtools/client/netmonitor/components/clear-button.js index 5ef1a73211fd..cccff81fb9dd 100644 --- a/devtools/client/netmonitor/components/clear-button.js +++ b/devtools/client/netmonitor/components/clear-button.js @@ -2,12 +2,12 @@ * 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 NetMonitorView */ + "use strict"; const { DOM } = require("devtools/client/shared/vendor/react"); -const { connect } = require("devtools/client/shared/vendor/react-redux"); const { L10N } = require("../l10n"); -const Actions = require("../actions/index"); const { button } = DOM; @@ -15,18 +15,15 @@ const { button } = DOM; * Clear button component * A type of tool button is responsible for cleaning network requests. */ -function ClearButton({ onClick }) { +function ClearButton() { return button({ id: "requests-menu-clear-button", className: "devtools-button devtools-clear-icon", title: L10N.getStr("netmonitor.toolbar.clear"), - onClick, + onClick: () => { + NetMonitorView.RequestsMenu.clear(); + }, }); } -module.exports = connect( - undefined, - dispatch => ({ - onClick: () => dispatch(Actions.clearRequests()) - }) -)(ClearButton); +module.exports = ClearButton; diff --git a/devtools/client/netmonitor/components/moz.build b/devtools/client/netmonitor/components/moz.build index bb5ad9b7dd9f..02655b710f23 100644 --- a/devtools/client/netmonitor/components/moz.build +++ b/devtools/client/netmonitor/components/moz.build @@ -5,12 +5,6 @@ DevToolsModules( 'clear-button.js', 'filter-buttons.js', - 'request-list-content.js', - 'request-list-empty.js', - 'request-list-header.js', - 'request-list-item.js', - 'request-list-tooltip.js', - 'request-list.js', 'search-box.js', 'summary-button.js', 'toggle-button.js', diff --git a/devtools/client/netmonitor/components/request-list-content.js b/devtools/client/netmonitor/components/request-list-content.js deleted file mode 100644 index c5f029600d2b..000000000000 --- a/devtools/client/netmonitor/components/request-list-content.js +++ /dev/null @@ -1,255 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/* globals NetMonitorView */ - -"use strict"; - -const { Task } = require("devtools/shared/task"); -const { createClass, createFactory, DOM } = require("devtools/client/shared/vendor/react"); -const { div } = DOM; -const Actions = require("../actions/index"); -const RequestListItem = createFactory(require("./request-list-item")); -const { connect } = require("devtools/client/shared/vendor/react-redux"); -const { setTooltipImageContent, - setTooltipStackTraceContent } = require("./request-list-tooltip"); -const { getDisplayedRequests, - getWaterfallScale } = require("../selectors/index"); -const { KeyCodes } = require("devtools/client/shared/keycodes"); - -// tooltip show/hide delay in ms -const REQUESTS_TOOLTIP_TOGGLE_DELAY = 500; - -/** - * Renders the actual contents of the request list. - */ -const RequestListContent = createClass({ - displayName: "RequestListContent", - - componentDidMount() { - // Set the CSS variables for waterfall scaling - this.setScalingStyles(); - - // Install event handler for displaying a tooltip - this.props.tooltip.startTogglingOnHover(this.refs.contentEl, this.onHover, { - toggleDelay: REQUESTS_TOOLTIP_TOGGLE_DELAY, - interactive: true - }); - - // Install event handler to hide the tooltip on scroll - this.refs.contentEl.addEventListener("scroll", this.onScroll, true); - }, - - componentWillUpdate() { - // Check if the list is scrolled to bottom, before UI update - this.shouldScrollBottom = this.isScrolledToBottom(); - }, - - componentDidUpdate(prevProps) { - // Update the CSS variables for waterfall scaling after props change - this.setScalingStyles(); - - // Keep the list scrolled to bottom if a new row was added - if (this.shouldScrollBottom) { - let node = this.refs.contentEl; - node.scrollTop = node.scrollHeight; - } - }, - - componentWillUnmount() { - this.refs.contentEl.removeEventListener("scroll", this.onScroll, true); - - // Uninstall the tooltip event handler - this.props.tooltip.stopTogglingOnHover(); - }, - - /** - * Set the CSS variables for waterfall scaling. If React supported setting CSS - * variables as part of the "style" property of a DOM element, we would use that. - * - * However, React doesn't support this, so we need to use a hack and update the - * DOM element directly: https://github.com/facebook/react/issues/6411 - */ - setScalingStyles(prevProps) { - const { scale } = this.props; - if (scale == this.currentScale) { - return; - } - - this.currentScale = scale; - - const { style } = this.refs.contentEl; - style.removeProperty("--timings-scale"); - style.removeProperty("--timings-rev-scale"); - style.setProperty("--timings-scale", scale); - style.setProperty("--timings-rev-scale", 1 / scale); - }, - - isScrolledToBottom() { - const { contentEl } = this.refs; - const lastChildEl = contentEl.lastElementChild; - - if (!lastChildEl) { - return false; - } - - let lastChildRect = lastChildEl.getBoundingClientRect(); - let contentRect = contentEl.getBoundingClientRect(); - - return (lastChildRect.height + lastChildRect.top) <= contentRect.bottom; - }, - - /** - * The predicate used when deciding whether a popup should be shown - * over a request item or not. - * - * @param nsIDOMNode target - * The element node currently being hovered. - * @param object tooltip - * The current tooltip instance. - * @return {Promise} - */ - onHover: Task.async(function* (target, tooltip) { - let itemEl = target.closest(".request-list-item"); - if (!itemEl) { - return false; - } - let itemId = itemEl.dataset.id; - if (!itemId) { - return false; - } - let requestItem = this.props.displayedRequests.find(r => r.id == itemId); - if (!requestItem) { - return false; - } - - if (requestItem.responseContent && target.closest(".requests-menu-icon-and-file")) { - return setTooltipImageContent(tooltip, itemEl, requestItem); - } else if (requestItem.cause && target.closest(".requests-menu-cause-stack")) { - return setTooltipStackTraceContent(tooltip, requestItem); - } - - return false; - }), - - /** - * Scroll listener for the requests menu view. - */ - onScroll() { - this.props.tooltip.hide(); - }, - - /** - * Handler for keyboard events. For arrow up/down, page up/down, home/end, - * move the selection up or down. - */ - onKeyDown(e) { - let delta; - - switch (e.keyCode) { - case KeyCodes.DOM_VK_UP: - case KeyCodes.DOM_VK_LEFT: - delta = -1; - break; - case KeyCodes.DOM_VK_DOWN: - case KeyCodes.DOM_VK_RIGHT: - delta = +1; - break; - case KeyCodes.DOM_VK_PAGE_UP: - delta = "PAGE_UP"; - break; - case KeyCodes.DOM_VK_PAGE_DOWN: - delta = "PAGE_DOWN"; - break; - case KeyCodes.DOM_VK_HOME: - delta = -Infinity; - break; - case KeyCodes.DOM_VK_END: - delta = +Infinity; - break; - } - - if (delta) { - // Prevent scrolling when pressing navigation keys. - e.preventDefault(); - e.stopPropagation(); - this.props.onSelectDelta(delta); - } - }, - - /** - * If selection has just changed (by keyboard navigation), don't keep the list - * scrolled to bottom, but allow scrolling up with the selection. - */ - onFocusedNodeChange() { - this.shouldScrollBottom = false; - }, - - /** - * If a focused item was unmounted, transfer the focus to the container element. - */ - onFocusedNodeUnmount() { - if (this.refs.contentEl) { - this.refs.contentEl.focus(); - } - }, - - render() { - const { selectedRequestId, - displayedRequests, - firstRequestStartedMillis, - onItemMouseDown, - onItemContextMenu, - onSecurityIconClick } = this.props; - - return div( - { - ref: "contentEl", - className: "requests-menu-contents", - tabIndex: 0, - onKeyDown: this.onKeyDown, - }, - displayedRequests.map((item, index) => RequestListItem({ - key: item.id, - item, - index, - isSelected: item.id === selectedRequestId, - firstRequestStartedMillis, - onMouseDown: e => onItemMouseDown(e, item.id), - onContextMenu: e => onItemContextMenu(e, item.id), - onSecurityIconClick: e => onSecurityIconClick(e, item), - onFocusedNodeChange: this.onFocusedNodeChange, - onFocusedNodeUnmount: this.onFocusedNodeUnmount, - })) - ); - }, -}); - -module.exports = connect( - state => ({ - displayedRequests: getDisplayedRequests(state), - selectedRequestId: state.requests.selectedId, - scale: getWaterfallScale(state), - firstRequestStartedMillis: state.requests.firstStartedMillis, - tooltip: NetMonitorView.RequestsMenu.tooltip, - }), - dispatch => ({ - onItemMouseDown: (e, item) => dispatch(Actions.selectRequest(item)), - onItemContextMenu: (e, item) => { - e.preventDefault(); - NetMonitorView.RequestsMenu.contextMenu.open(e); - }, - onSelectDelta: (delta) => dispatch(Actions.selectDelta(delta)), - /** - * A handler that opens the security tab in the details view if secure or - * broken security indicator is clicked. - */ - onSecurityIconClick: (e, item) => { - const { securityState } = item; - if (securityState && securityState !== "insecure") { - // Choose the security tab. - NetMonitorView.NetworkDetails.widget.selectedIndex = 5; - } - }, - }) -)(RequestListContent); diff --git a/devtools/client/netmonitor/components/request-list-empty.js b/devtools/client/netmonitor/components/request-list-empty.js deleted file mode 100644 index f4fe56bc1c70..000000000000 --- a/devtools/client/netmonitor/components/request-list-empty.js +++ /dev/null @@ -1,65 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/* globals NetMonitorView */ - -"use strict"; - -const { createClass, PropTypes, DOM } = require("devtools/client/shared/vendor/react"); -const { L10N } = require("../l10n"); -const { div, span, button } = DOM; -const { connect } = require("devtools/client/shared/vendor/react-redux"); - -/** - * UI displayed when the request list is empty. Contains instructions on reloading - * the page and on triggering performance analysis of the page. - */ -const RequestListEmptyNotice = createClass({ - displayName: "RequestListEmptyNotice", - - propTypes: { - onReloadClick: PropTypes.func.isRequired, - onPerfClick: PropTypes.func.isRequired, - }, - - render() { - return div( - { - id: "requests-menu-empty-notice", - className: "request-list-empty-notice", - }, - div({ id: "notice-reload-message" }, - span(null, L10N.getStr("netmonitor.reloadNotice1")), - button( - { - id: "requests-menu-reload-notice-button", - className: "devtools-toolbarbutton", - "data-standalone": true, - onClick: this.props.onReloadClick, - }, - L10N.getStr("netmonitor.reloadNotice2") - ), - span(null, L10N.getStr("netmonitor.reloadNotice3")) - ), - div({ id: "notice-perf-message" }, - span(null, L10N.getStr("netmonitor.perfNotice1")), - button({ - id: "requests-menu-perf-notice-button", - title: L10N.getStr("netmonitor.perfNotice3"), - className: "devtools-button", - "data-standalone": true, - onClick: this.props.onPerfClick, - }), - span(null, L10N.getStr("netmonitor.perfNotice2")) - ) - ); - } -}); - -module.exports = connect( - undefined, - dispatch => ({ - onPerfClick: e => NetMonitorView.toggleFrontendMode(), - onReloadClick: e => NetMonitorView.reloadPage(), - }) -)(RequestListEmptyNotice); diff --git a/devtools/client/netmonitor/components/request-list-header.js b/devtools/client/netmonitor/components/request-list-header.js deleted file mode 100644 index d28226eccf2b..000000000000 --- a/devtools/client/netmonitor/components/request-list-header.js +++ /dev/null @@ -1,197 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* globals document */ - -"use strict"; - -const { createClass, PropTypes, DOM } = require("devtools/client/shared/vendor/react"); -const { div, button } = DOM; -const { connect } = require("devtools/client/shared/vendor/react-redux"); -const { L10N } = require("../l10n"); -const { getWaterfallScale } = require("../selectors/index"); -const Actions = require("../actions/index"); -const WaterfallBackground = require("../waterfall-background"); - -// ms -const REQUESTS_WATERFALL_HEADER_TICKS_MULTIPLE = 5; -// px -const REQUESTS_WATERFALL_HEADER_TICKS_SPACING_MIN = 60; - -const REQUEST_TIME_DECIMALS = 2; - -const HEADERS = [ - { name: "status", label: "status3" }, - { name: "method" }, - { name: "file", boxName: "icon-and-file" }, - { name: "domain", boxName: "security-and-domain" }, - { name: "cause" }, - { name: "type" }, - { name: "transferred" }, - { name: "size" }, - { name: "waterfall" } -]; - -/** - * Render the request list header with sorting arrows for columns. - * Displays tick marks in the waterfall column header. - * Also draws the waterfall background canvas and updates it when needed. - */ -const RequestListHeader = createClass({ - displayName: "RequestListHeader", - - propTypes: { - sort: PropTypes.object, - scale: PropTypes.number, - waterfallWidth: PropTypes.number, - onHeaderClick: PropTypes.func.isRequired, - }, - - componentDidMount() { - this.background = new WaterfallBackground(document); - this.background.draw(this.props); - }, - - componentDidUpdate() { - this.background.draw(this.props); - }, - - componentWillUnmount() { - this.background.destroy(); - this.background = null; - }, - - render() { - const { sort, scale, waterfallWidth, onHeaderClick } = this.props; - - return div( - { id: "requests-menu-toolbar", className: "devtools-toolbar" }, - div({ id: "toolbar-labels" }, - HEADERS.map(header => { - const name = header.name; - const boxName = header.boxName || name; - const label = L10N.getStr(`netmonitor.toolbar.${header.label || name}`); - - let sorted, sortedTitle; - const active = sort.type == name ? true : undefined; - if (active) { - sorted = sort.ascending ? "ascending" : "descending"; - sortedTitle = L10N.getStr(sort.ascending - ? "networkMenu.sortedAsc" - : "networkMenu.sortedDesc"); - } - - return div( - { - id: `requests-menu-${boxName}-header-box`, - key: name, - className: `requests-menu-header requests-menu-${boxName}`, - // Used to style the next column. - "data-active": active, - }, - button( - { - id: `requests-menu-${name}-button`, - className: `requests-menu-header-button requests-menu-${name}`, - "data-sorted": sorted, - title: sortedTitle, - onClick: () => onHeaderClick(name), - }, - name == "waterfall" ? WaterfallLabel(waterfallWidth, scale, label) - : div({ className: "button-text" }, label), - div({ className: "button-icon" }) - ) - ); - }) - ) - ); - } -}); - -/** - * Build the waterfall header - timing tick marks with the right spacing - */ -function waterfallDivisionLabels(waterfallWidth, scale) { - let labels = []; - - // Build new millisecond tick labels... - let timingStep = REQUESTS_WATERFALL_HEADER_TICKS_MULTIPLE; - let scaledStep = scale * timingStep; - - // Ignore any divisions that would end up being too close to each other. - while (scaledStep < REQUESTS_WATERFALL_HEADER_TICKS_SPACING_MIN) { - scaledStep *= 2; - } - - // Insert one label for each division on the current scale. - for (let x = 0; x < waterfallWidth; x += scaledStep) { - let millisecondTime = x / scale; - - let normalizedTime = millisecondTime; - let divisionScale = "millisecond"; - - // If the division is greater than 1 minute. - if (normalizedTime > 60000) { - normalizedTime /= 60000; - divisionScale = "minute"; - } else if (normalizedTime > 1000) { - // If the division is greater than 1 second. - normalizedTime /= 1000; - divisionScale = "second"; - } - - // Showing too many decimals is bad UX. - if (divisionScale == "millisecond") { - normalizedTime |= 0; - } else { - normalizedTime = L10N.numberWithDecimals(normalizedTime, REQUEST_TIME_DECIMALS); - } - - let width = (x + scaledStep | 0) - (x | 0); - // Adjust the first marker for the borders - if (x == 0) { - width -= 2; - } - // Last marker doesn't need a width specified at all - if (x + scaledStep >= waterfallWidth) { - width = undefined; - } - - labels.push(div( - { - key: labels.length, - className: "requests-menu-timings-division", - "data-division-scale": divisionScale, - style: { width } - }, - L10N.getFormatStr("networkMenu." + divisionScale, normalizedTime) - )); - } - - return labels; -} - -function WaterfallLabel(waterfallWidth, scale, label) { - let className = "button-text requests-menu-waterfall-label-wrapper"; - - if (scale != null) { - label = waterfallDivisionLabels(waterfallWidth, scale); - className += " requests-menu-waterfall-visible"; - } - - return div({ className }, label); -} - -module.exports = connect( - state => ({ - sort: state.sort, - scale: getWaterfallScale(state), - waterfallWidth: state.ui.waterfallWidth, - firstRequestStartedMillis: state.requests.firstStartedMillis, - timingMarkers: state.timingMarkers, - }), - dispatch => ({ - onHeaderClick: type => dispatch(Actions.sortBy(type)), - }) -)(RequestListHeader); diff --git a/devtools/client/netmonitor/components/request-list-item.js b/devtools/client/netmonitor/components/request-list-item.js deleted file mode 100644 index a7976ea2ae29..000000000000 --- a/devtools/client/netmonitor/components/request-list-item.js +++ /dev/null @@ -1,346 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const { createClass, PropTypes, DOM } = require("devtools/client/shared/vendor/react"); -const { div, span, img } = DOM; -const { L10N } = require("../l10n"); -const { getFormattedSize } = require("../utils/format-utils"); -const { getAbbreviatedMimeType } = require("../request-utils"); - -/** - * Render one row in the request list. - */ -const RequestListItem = createClass({ - displayName: "RequestListItem", - - propTypes: { - item: PropTypes.object.isRequired, - index: PropTypes.number.isRequired, - isSelected: PropTypes.bool.isRequired, - firstRequestStartedMillis: PropTypes.number.isRequired, - onContextMenu: PropTypes.func.isRequired, - onMouseDown: PropTypes.func.isRequired, - onSecurityIconClick: PropTypes.func.isRequired, - }, - - componentDidMount() { - if (this.props.isSelected) { - this.refs.el.focus(); - } - }, - - shouldComponentUpdate(nextProps) { - return !relevantPropsEqual(this.props.item, nextProps.item) - || this.props.index !== nextProps.index - || this.props.isSelected !== nextProps.isSelected - || this.props.firstRequestStartedMillis !== nextProps.firstRequestStartedMillis; - }, - - componentDidUpdate(prevProps) { - if (!prevProps.isSelected && this.props.isSelected) { - this.refs.el.focus(); - if (this.props.onFocusedNodeChange) { - this.props.onFocusedNodeChange(); - } - } - }, - - componentWillUnmount() { - // If this node is being destroyed and has focus, transfer the focus manually - // to the parent tree component. Otherwise, the focus will get lost and keyboard - // navigation in the tree will stop working. This is a workaround for a XUL bug. - // See bugs 1259228 and 1152441 for details. - // DE-XUL: Remove this hack once all usages are only in HTML documents. - if (this.props.isSelected) { - this.refs.el.blur(); - if (this.props.onFocusedNodeUnmount) { - this.props.onFocusedNodeUnmount(); - } - } - }, - - render() { - const { - item, - index, - isSelected, - firstRequestStartedMillis, - onContextMenu, - onMouseDown, - onSecurityIconClick - } = this.props; - - let classList = [ "request-list-item" ]; - if (isSelected) { - classList.push("selected"); - } - classList.push(index % 2 ? "odd" : "even"); - - return div( - { - ref: "el", - className: classList.join(" "), - "data-id": item.id, - tabIndex: 0, - onContextMenu, - onMouseDown, - }, - StatusColumn(item), - MethodColumn(item), - FileColumn(item), - DomainColumn(item, onSecurityIconClick), - CauseColumn(item), - TypeColumn(item), - TransferredSizeColumn(item), - ContentSizeColumn(item), - WaterfallColumn(item, firstRequestStartedMillis) - ); - } -}); - -/** - * Used by shouldComponentUpdate: compare two items, and compare only properties - * relevant for rendering the RequestListItem. Other properties (like request and - * response headers, cookies, bodies) are ignored. These are very useful for the - * sidebar details, but not here. - */ -const RELEVANT_ITEM_PROPS = [ - "status", - "statusText", - "fromCache", - "fromServiceWorker", - "method", - "url", - "responseContentDataUri", - "remoteAddress", - "securityState", - "cause", - "mimeType", - "contentSize", - "transferredSize", - "startedMillis", - "totalTime", - "eventTimings", -]; - -function relevantPropsEqual(item1, item2) { - return item1 === item2 || RELEVANT_ITEM_PROPS.every(p => item1[p] === item2[p]); -} - -function StatusColumn(item) { - const { status, statusText, fromCache, fromServiceWorker } = item; - - let code, title; - - if (status) { - if (fromCache) { - code = "cached"; - } else if (fromServiceWorker) { - code = "service worker"; - } else { - code = status; - } - - if (statusText) { - title = `${status} ${statusText}`; - if (fromCache) { - title += " (cached)"; - } - if (fromServiceWorker) { - title += " (service worker)"; - } - } - } - - return div({ className: "requests-menu-subitem requests-menu-status", title }, - div({ className: "requests-menu-status-icon", "data-code": code }), - span({ className: "subitem-label requests-menu-status-code" }, status) - ); -} - -function MethodColumn(item) { - const { method } = item; - return div({ className: "requests-menu-subitem requests-menu-method-box" }, - span({ className: "subitem-label requests-menu-method" }, method) - ); -} - -function FileColumn(item) { - const { urlDetails, responseContentDataUri } = item; - - return div({ className: "requests-menu-subitem requests-menu-icon-and-file" }, - img({ - className: "requests-menu-icon", - src: responseContentDataUri, - hidden: !responseContentDataUri, - "data-type": responseContentDataUri ? "thumbnail" : undefined - }), - div( - { - className: "subitem-label requests-menu-file", - title: urlDetails.unicodeUrl - }, - urlDetails.baseNameWithQuery - ) - ); -} - -function DomainColumn(item, onSecurityIconClick) { - const { urlDetails, remoteAddress, securityState } = item; - - let iconClassList = [ "requests-security-state-icon" ]; - let iconTitle; - if (urlDetails.isLocal) { - iconClassList.push("security-state-local"); - iconTitle = L10N.getStr("netmonitor.security.state.secure"); - } else if (securityState) { - iconClassList.push(`security-state-${securityState}`); - iconTitle = L10N.getStr(`netmonitor.security.state.${securityState}`); - } - - let title = urlDetails.host + (remoteAddress ? ` (${remoteAddress})` : ""); - - return div( - { className: "requests-menu-subitem requests-menu-security-and-domain" }, - div({ - className: iconClassList.join(" "), - title: iconTitle, - onClick: onSecurityIconClick, - }), - span({ className: "subitem-label requests-menu-domain", title }, urlDetails.host) - ); -} - -function CauseColumn(item) { - const { cause } = item; - - let causeType = ""; - let causeUri = undefined; - let causeHasStack = false; - - if (cause) { - causeType = cause.type; - causeUri = cause.loadingDocumentUri; - causeHasStack = cause.stacktrace && cause.stacktrace.length > 0; - } - - return div( - { className: "requests-menu-subitem requests-menu-cause", title: causeUri }, - span({ className: "requests-menu-cause-stack", hidden: !causeHasStack }, "JS"), - span({ className: "subitem-label" }, causeType) - ); -} - -const CONTENT_MIME_TYPE_ABBREVIATIONS = { - "ecmascript": "js", - "javascript": "js", - "x-javascript": "js" -}; - -function TypeColumn(item) { - const { mimeType } = item; - let abbrevType; - if (mimeType) { - abbrevType = getAbbreviatedMimeType(mimeType); - abbrevType = CONTENT_MIME_TYPE_ABBREVIATIONS[abbrevType] || abbrevType; - } - - return div( - { className: "requests-menu-subitem requests-menu-type", title: mimeType }, - span({ className: "subitem-label" }, abbrevType) - ); -} - -function TransferredSizeColumn(item) { - const { transferredSize, fromCache, fromServiceWorker } = item; - - let text; - let className = "subitem-label"; - if (fromCache) { - text = L10N.getStr("networkMenu.sizeCached"); - className += " theme-comment"; - } else if (fromServiceWorker) { - text = L10N.getStr("networkMenu.sizeServiceWorker"); - className += " theme-comment"; - } else if (typeof transferredSize == "number") { - text = getFormattedSize(transferredSize); - } else if (transferredSize === null) { - text = L10N.getStr("networkMenu.sizeUnavailable"); - } - - return div( - { className: "requests-menu-subitem requests-menu-transferred", title: text }, - span({ className }, text) - ); -} - -function ContentSizeColumn(item) { - const { contentSize } = item; - - let text; - if (typeof contentSize == "number") { - text = getFormattedSize(contentSize); - } - - return div( - { className: "requests-menu-subitem subitem-label requests-menu-size", title: text }, - span({ className: "subitem-label" }, text) - ); -} - -// List of properties of the timing info we want to create boxes for -const TIMING_KEYS = ["blocked", "dns", "connect", "send", "wait", "receive"]; - -function timingBoxes(item) { - const { eventTimings, totalTime, fromCache, fromServiceWorker } = item; - let boxes = []; - - if (fromCache || fromServiceWorker) { - return boxes; - } - - if (eventTimings) { - // Add a set of boxes representing timing information. - for (let key of TIMING_KEYS) { - let width = eventTimings.timings[key]; - - // Don't render anything if it surely won't be visible. - // One millisecond == one unscaled pixel. - if (width > 0) { - boxes.push(div({ - key, - className: "requests-menu-timings-box " + key, - style: { width } - })); - } - } - } - - if (typeof totalTime == "number") { - let text = L10N.getFormatStr("networkMenu.totalMS", totalTime); - boxes.push(div({ - key: "total", - className: "requests-menu-timings-total", - title: text - }, text)); - } - - return boxes; -} - -function WaterfallColumn(item, firstRequestStartedMillis) { - const startedDeltaMillis = item.startedMillis - firstRequestStartedMillis; - const paddingInlineStart = `${startedDeltaMillis}px`; - - return div({ className: "requests-menu-subitem requests-menu-waterfall" }, - div( - { className: "requests-menu-timings", style: { paddingInlineStart } }, - timingBoxes(item) - ) - ); -} - -module.exports = RequestListItem; diff --git a/devtools/client/netmonitor/components/request-list-tooltip.js b/devtools/client/netmonitor/components/request-list-tooltip.js deleted file mode 100644 index 2bea502cf9e3..000000000000 --- a/devtools/client/netmonitor/components/request-list-tooltip.js +++ /dev/null @@ -1,107 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* globals gNetwork, NetMonitorController */ - -"use strict"; - -const { Task } = require("devtools/shared/task"); -const { formDataURI } = require("../request-utils"); -const { WEBCONSOLE_L10N } = require("../l10n"); -const { setImageTooltip, - getImageDimensions } = require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper"); - -// px -const REQUESTS_TOOLTIP_IMAGE_MAX_DIM = 400; -// px -const REQUESTS_TOOLTIP_STACK_TRACE_WIDTH = 600; - -const HTML_NS = "http://www.w3.org/1999/xhtml"; - -const setTooltipImageContent = Task.async(function* (tooltip, itemEl, requestItem) { - let { mimeType, text, encoding } = requestItem.responseContent.content; - - if (!mimeType || !mimeType.includes("image/")) { - return false; - } - - let string = yield gNetwork.getString(text); - let src = formDataURI(mimeType, encoding, string); - let maxDim = REQUESTS_TOOLTIP_IMAGE_MAX_DIM; - let { naturalWidth, naturalHeight } = yield getImageDimensions(tooltip.doc, src); - let options = { maxDim, naturalWidth, naturalHeight }; - setImageTooltip(tooltip, tooltip.doc, src, options); - - return itemEl.querySelector(".requests-menu-icon"); -}); - -const setTooltipStackTraceContent = Task.async(function* (tooltip, requestItem) { - let {stacktrace} = requestItem.cause; - - if (!stacktrace || stacktrace.length == 0) { - return false; - } - - let doc = tooltip.doc; - let el = doc.createElementNS(HTML_NS, "div"); - el.className = "stack-trace-tooltip devtools-monospace"; - - for (let f of stacktrace) { - let { functionName, filename, lineNumber, columnNumber, asyncCause } = f; - - if (asyncCause) { - // if there is asyncCause, append a "divider" row into the trace - let asyncFrameEl = doc.createElementNS(HTML_NS, "div"); - asyncFrameEl.className = "stack-frame stack-frame-async"; - asyncFrameEl.textContent = - WEBCONSOLE_L10N.getFormatStr("stacktrace.asyncStack", asyncCause); - el.appendChild(asyncFrameEl); - } - - // Parse a source name in format "url -> url" - let sourceUrl = filename.split(" -> ").pop(); - - let frameEl = doc.createElementNS(HTML_NS, "div"); - frameEl.className = "stack-frame stack-frame-call"; - - let funcEl = doc.createElementNS(HTML_NS, "span"); - funcEl.className = "stack-frame-function-name"; - funcEl.textContent = - functionName || WEBCONSOLE_L10N.getStr("stacktrace.anonymousFunction"); - frameEl.appendChild(funcEl); - - let sourceEl = doc.createElementNS(HTML_NS, "span"); - sourceEl.className = "stack-frame-source-name"; - frameEl.appendChild(sourceEl); - - let sourceInnerEl = doc.createElementNS(HTML_NS, "span"); - sourceInnerEl.className = "stack-frame-source-name-inner"; - sourceEl.appendChild(sourceInnerEl); - - sourceInnerEl.textContent = sourceUrl; - sourceInnerEl.title = sourceUrl; - - let lineEl = doc.createElementNS(HTML_NS, "span"); - lineEl.className = "stack-frame-line"; - lineEl.textContent = `:${lineNumber}:${columnNumber}`; - sourceInnerEl.appendChild(lineEl); - - frameEl.addEventListener("click", () => { - // hide the tooltip immediately, not after delay - tooltip.hide(); - NetMonitorController.viewSourceInDebugger(filename, lineNumber); - }, false); - - el.appendChild(frameEl); - } - - tooltip.setContent(el, {width: REQUESTS_TOOLTIP_STACK_TRACE_WIDTH}); - - return true; -}); - -module.exports = { - setTooltipImageContent, - setTooltipStackTraceContent, -}; diff --git a/devtools/client/netmonitor/components/request-list.js b/devtools/client/netmonitor/components/request-list.js deleted file mode 100644 index 7048fdb4b629..000000000000 --- a/devtools/client/netmonitor/components/request-list.js +++ /dev/null @@ -1,34 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const { createFactory, PropTypes, DOM } = require("devtools/client/shared/vendor/react"); -const { div } = DOM; -const { connect } = require("devtools/client/shared/vendor/react-redux"); -const RequestListHeader = createFactory(require("./request-list-header")); -const RequestListEmptyNotice = createFactory(require("./request-list-empty")); -const RequestListContent = createFactory(require("./request-list-content")); - -/** - * Renders the request list - header, empty text, the actual content with rows - */ -const RequestList = function ({ isEmpty }) { - return div({ className: "request-list-container" }, - RequestListHeader(), - isEmpty ? RequestListEmptyNotice() : RequestListContent() - ); -}; - -RequestList.displayName = "RequestList"; - -RequestList.propTypes = { - isEmpty: PropTypes.bool.isRequired, -}; - -module.exports = connect( - state => ({ - isEmpty: state.requests.requests.isEmpty() - }) -)(RequestList); diff --git a/devtools/client/netmonitor/components/summary-button.js b/devtools/client/netmonitor/components/summary-button.js index 7b8980d4ec5c..9465d3147b6c 100644 --- a/devtools/client/netmonitor/components/summary-button.js +++ b/devtools/client/netmonitor/components/summary-button.js @@ -14,7 +14,7 @@ const { DOM, PropTypes } = require("devtools/client/shared/vendor/react"); const { connect } = require("devtools/client/shared/vendor/react-redux"); const { PluralForm } = require("devtools/shared/plural-form"); const { L10N } = require("../l10n"); -const { getDisplayedRequestsSummary } = require("../selectors/index"); +const { getSummary } = require("../selectors/index"); const { button, span } = DOM; @@ -22,12 +22,14 @@ function SummaryButton({ summary, triggerSummary, }) { - let { count, bytes, millis } = summary; + let { count, totalBytes, totalMillis } = summary; const text = (count === 0) ? L10N.getStr("networkMenu.empty") : PluralForm.get(count, L10N.getStr("networkMenu.summary")) .replace("#1", count) - .replace("#2", L10N.numberWithDecimals(bytes / 1024, CONTENT_SIZE_DECIMALS)) - .replace("#3", L10N.numberWithDecimals(millis / 1000, REQUEST_TIME_DECIMALS)); + .replace("#2", L10N.numberWithDecimals(totalBytes / 1024, + CONTENT_SIZE_DECIMALS)) + .replace("#3", L10N.numberWithDecimals(totalMillis / 1000, + REQUEST_TIME_DECIMALS)); return button({ id: "requests-menu-network-summary-button", @@ -45,7 +47,7 @@ SummaryButton.propTypes = { module.exports = connect( (state) => ({ - summary: getDisplayedRequestsSummary(state), + summary: getSummary(state), }), (dispatch) => ({ triggerSummary: () => { diff --git a/devtools/client/netmonitor/components/toggle-button.js b/devtools/client/netmonitor/components/toggle-button.js index 57d7f3a924e1..2a3cea027529 100644 --- a/devtools/client/netmonitor/components/toggle-button.js +++ b/devtools/client/netmonitor/components/toggle-button.js @@ -2,20 +2,21 @@ * 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 NetMonitorView */ + "use strict"; const { DOM, PropTypes } = require("devtools/client/shared/vendor/react"); const { connect } = require("devtools/client/shared/vendor/react-redux"); const { L10N } = require("../l10n"); const Actions = require("../actions/index"); -const { isSidebarToggleButtonDisabled } = require("../selectors/index"); const { button } = DOM; function ToggleButton({ disabled, open, - onToggle, + triggerSidebar, }) { let className = ["devtools-button"]; if (!open) { @@ -31,21 +32,34 @@ function ToggleButton({ title, disabled, tabIndex: "0", - onMouseDown: onToggle, + onMouseDown: triggerSidebar, }); } ToggleButton.propTypes = { disabled: PropTypes.bool.isRequired, - onToggle: PropTypes.func.isRequired, + triggerSidebar: PropTypes.func.isRequired, }; module.exports = connect( (state) => ({ - disabled: isSidebarToggleButtonDisabled(state), - open: state.ui.sidebarOpen, + disabled: state.requests.items.length === 0, + open: state.ui.sidebar.open, }), (dispatch) => ({ - onToggle: () => dispatch(Actions.toggleSidebar()) + triggerSidebar: () => { + dispatch(Actions.toggleSidebar()); + + let requestsMenu = NetMonitorView.RequestsMenu; + let selectedIndex = requestsMenu.selectedIndex; + + // Make sure there's a selection if the button is pressed, to avoid + // showing an empty network details pane. + if (selectedIndex == -1 && requestsMenu.itemCount) { + requestsMenu.selectedIndex = 0; + } else { + requestsMenu.selectedIndex = -1; + } + }, }) )(ToggleButton); diff --git a/devtools/client/netmonitor/constants.js b/devtools/client/netmonitor/constants.js index de98cf7c29d0..48f520e64401 100644 --- a/devtools/client/netmonitor/constants.js +++ b/devtools/client/netmonitor/constants.js @@ -11,40 +11,12 @@ const general = { }; const actionTypes = { - BATCH_ACTIONS: "BATCH_ACTIONS", - BATCH_ENABLE: "BATCH_ENABLE", - ADD_TIMING_MARKER: "ADD_TIMING_MARKER", - CLEAR_TIMING_MARKERS: "CLEAR_TIMING_MARKERS", - ADD_REQUEST: "ADD_REQUEST", - UPDATE_REQUEST: "UPDATE_REQUEST", - CLEAR_REQUESTS: "CLEAR_REQUESTS", - CLONE_SELECTED_REQUEST: "CLONE_SELECTED_REQUEST", - REMOVE_SELECTED_CUSTOM_REQUEST: "REMOVE_SELECTED_CUSTOM_REQUEST", - SELECT_REQUEST: "SELECT_REQUEST", - PRESELECT_REQUEST: "PRESELECT_REQUEST", - SORT_BY: "SORT_BY", TOGGLE_FILTER_TYPE: "TOGGLE_FILTER_TYPE", ENABLE_FILTER_TYPE_ONLY: "ENABLE_FILTER_TYPE_ONLY", SET_FILTER_TEXT: "SET_FILTER_TEXT", OPEN_SIDEBAR: "OPEN_SIDEBAR", - WATERFALL_RESIZE: "WATERFALL_RESIZE", + TOGGLE_SIDEBAR: "TOGGLE_SIDEBAR", + UPDATE_REQUESTS: "UPDATE_REQUESTS", }; -// Descriptions for what this frontend is currently doing. -const ACTIVITY_TYPE = { - // Standing by and handling requests normally. - NONE: 0, - - // Forcing the target to reload with cache enabled or disabled. - RELOAD: { - WITH_CACHE_ENABLED: 1, - WITH_CACHE_DISABLED: 2, - WITH_CACHE_DEFAULT: 3 - }, - - // Enabling or disabling the cache without triggering a reload. - ENABLE_CACHE: 3, - DISABLE_CACHE: 4 -}; - -module.exports = Object.assign({ ACTIVITY_TYPE }, general, actionTypes); +module.exports = Object.assign({}, general, actionTypes); diff --git a/devtools/client/netmonitor/custom-request-view.js b/devtools/client/netmonitor/custom-request-view.js index f7ebf27e3d13..06871a61f483 100644 --- a/devtools/client/netmonitor/custom-request-view.js +++ b/devtools/client/netmonitor/custom-request-view.js @@ -7,11 +7,12 @@ "use strict"; const { Task } = require("devtools/shared/task"); -const { writeHeaderText, - getKeyWithEvent, - getUrlQuery, - parseQueryString } = require("./request-utils"); -const Actions = require("./actions/index"); +const { + writeHeaderText, + getKeyWithEvent, + getUrlQuery, + parseQueryString, +} = require("./request-utils"); /** * Functions handling the custom request view. @@ -75,41 +76,37 @@ CustomRequestView.prototype = { */ onUpdate: function (field) { let selectedItem = NetMonitorView.RequestsMenu.selectedItem; - let store = NetMonitorView.RequestsMenu.store; let value; switch (field) { case "method": value = $("#custom-method-value").value.trim(); - store.dispatch(Actions.updateRequest(selectedItem.id, { method: value })); + selectedItem.attachment.method = value; break; case "url": value = $("#custom-url-value").value; this.updateCustomQuery(value); - store.dispatch(Actions.updateRequest(selectedItem.id, { url: value })); + selectedItem.attachment.url = value; break; case "query": let query = $("#custom-query-value").value; this.updateCustomUrl(query); + field = "url"; value = $("#custom-url-value").value; - store.dispatch(Actions.updateRequest(selectedItem.id, { url: value })); + selectedItem.attachment.url = value; break; case "body": value = $("#custom-postdata-value").value; - store.dispatch(Actions.updateRequest(selectedItem.id, { - requestPostData: { - postData: { text: value } - } - })); + selectedItem.attachment.requestPostData = { postData: { text: value } }; break; case "headers": let headersText = $("#custom-headers-value").value; value = parseHeadersText(headersText); - store.dispatch(Actions.updateRequest(selectedItem.id, { - requestHeaders: { headers: value } - })); + selectedItem.attachment.requestHeaders = { headers: value }; break; } + + NetMonitorView.RequestsMenu.updateMenuView(selectedItem, field, value); }, /** @@ -164,7 +161,7 @@ function parseHeadersText(text) { * Parse readable text list of a query string. * * @param string text - * Text of query string representation + * Text of query string represetation * @return array * Array of query params {name, value} */ diff --git a/devtools/client/netmonitor/details-view.js b/devtools/client/netmonitor/details-view.js index e0e992ef10e5..97687323a131 100644 --- a/devtools/client/netmonitor/details-view.js +++ b/devtools/client/netmonitor/details-view.js @@ -2,14 +2,14 @@ * 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-globals-from ./netmonitor-controller.js */ /* eslint-disable mozilla/reject-some-requires */ -/* globals window, dumpn, $, NetMonitorView, gNetwork */ +/* globals dumpn, $, NetMonitorView, gNetwork */ "use strict"; const promise = require("promise"); const EventEmitter = require("devtools/shared/event-emitter"); -const Editor = require("devtools/client/sourceeditor/editor"); const { Heritage } = require("devtools/client/shared/widgets/view-helpers"); const { Task } = require("devtools/shared/task"); const { ToolSidebar } = require("devtools/client/framework/sidebar"); @@ -267,6 +267,10 @@ DetailsView.prototype = { // Tab is selected but not dirty. We're done here. populated[tab] = true; window.emit(EVENTS.TAB_UPDATED); + + if (NetMonitorController.isConnected()) { + NetMonitorView.RequestsMenu.ensureSelectedItemIsVisible(); + } } } else if (viewState.dirty[tab]) { // Tab is dirty but no longer selected. Don't refresh it now, it'll be @@ -324,7 +328,7 @@ DetailsView.prototype = { } else { code = data.status; } - $("#headers-summary-status-circle").setAttribute("data-code", code); + $("#headers-summary-status-circle").setAttribute("code", code); $("#headers-summary-status-value").setAttribute("value", data.status + " " + data.statusText); $("#headers-summary-status").removeAttribute("hidden"); diff --git a/devtools/client/netmonitor/har/har-builder.js b/devtools/client/netmonitor/har/har-builder.js index 698be8dcfd01..565a4be0973c 100644 --- a/devtools/client/netmonitor/har/har-builder.js +++ b/devtools/client/netmonitor/har/har-builder.js @@ -63,7 +63,9 @@ HarBuilder.prototype = { let log = this.buildLog(); // Build entries. - for (let file of this._options.items) { + let items = this._options.items; + for (let i = 0; i < items.length; i++) { + let file = items[i].attachment; log.entries.push(this.buildEntry(log, file)); } diff --git a/devtools/client/netmonitor/har/har-collector.js b/devtools/client/netmonitor/har/har-collector.js index 315066bf7572..a55326a51e16 100644 --- a/devtools/client/netmonitor/har/har-collector.js +++ b/devtools/client/netmonitor/har/har-collector.js @@ -201,7 +201,9 @@ HarCollector.prototype = { this.files.set(actor, file); // Mimic the Net panel data structure - this.items.push(file); + this.items.push({ + attachment: file + }); }, onNetworkEventUpdate: function (type, packet) { 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 564eea991f99..882088cd19bd 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 @@ -16,7 +16,7 @@ function* throttleUploadTest(actuallyThrottle) { info("Starting test... (actuallyThrottle = " + actuallyThrottle + ")"); - let { NetMonitorController, NetMonitorView } = monitor.panelWin; + let { NetMonitorView } = monitor.panelWin; let { RequestsMenu } = NetMonitorView; const size = 4096; @@ -32,7 +32,7 @@ function* throttleUploadTest(actuallyThrottle) { uploadBPSMax: uploadSize, }, }; - let client = NetMonitorController.webConsoleClient; + let client = monitor._controller.webConsoleClient; info("sending throttle request"); let deferred = promise.defer(); diff --git a/devtools/client/netmonitor/middleware/batching.js b/devtools/client/netmonitor/middleware/batching.js deleted file mode 100644 index bf53d787bb0c..000000000000 --- a/devtools/client/netmonitor/middleware/batching.js +++ /dev/null @@ -1,132 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const { BATCH_ACTIONS, BATCH_ENABLE, BATCH_RESET } = require("../constants"); - -// ms -const REQUESTS_REFRESH_RATE = 50; - -/** - * Middleware that watches for actions with a "batch = true" value in their meta field. - * These actions are queued and dispatched as one batch after a timeout. - * Special actions that are handled by this middleware: - * - BATCH_ENABLE can be used to enable and disable the batching. - * - BATCH_RESET discards the actions that are currently in the queue. - */ -function batchingMiddleware(store) { - return next => { - let queuedActions = []; - let enabled = true; - let flushTask = null; - - return action => { - if (action.type === BATCH_ENABLE) { - return setEnabled(action.enabled); - } - - if (action.type === BATCH_RESET) { - return resetQueue(); - } - - if (action.meta && action.meta.batch) { - if (!enabled) { - next(action); - return Promise.resolve(); - } - - queuedActions.push(action); - - if (!flushTask) { - flushTask = new DelayedTask(flushActions, REQUESTS_REFRESH_RATE); - } - - return flushTask.promise; - } - - return next(action); - }; - - function setEnabled(value) { - enabled = value; - - // If disabling the batching, flush the actions that have been queued so far - if (!enabled && flushTask) { - flushTask.runNow(); - } - } - - function resetQueue() { - queuedActions = []; - - if (flushTask) { - flushTask.cancel(); - flushTask = null; - } - } - - function flushActions() { - const actions = queuedActions; - queuedActions = []; - - next({ - type: BATCH_ACTIONS, - actions, - }); - - flushTask = null; - } - }; -} - -/** - * Create a delayed task that calls the specified task function after a delay. - */ -function DelayedTask(taskFn, delay) { - this._promise = new Promise((resolve, reject) => { - this.runTask = (cancel) => { - if (cancel) { - reject("Task cancelled"); - } else { - taskFn(); - resolve(); - } - this.runTask = null; - }; - this.timeout = setTimeout(this.runTask, delay); - }).catch(console.error); -} - -DelayedTask.prototype = { - /** - * Return a promise that is resolved after the task is performed or canceled. - */ - get promise() { - return this._promise; - }, - - /** - * Cancel the execution of the task. - */ - cancel() { - clearTimeout(this.timeout); - if (this.runTask) { - this.runTask(true); - } - }, - - /** - * Execute the scheduled task immediately, without waiting for the timeout. - * Resolves the promise correctly. - */ - runNow() { - clearTimeout(this.timeout); - if (this.runTask) { - this.runTask(); - } - } -}; - -module.exports = batchingMiddleware; diff --git a/devtools/client/netmonitor/middleware/moz.build b/devtools/client/netmonitor/middleware/moz.build deleted file mode 100644 index 19c8f8b69de3..000000000000 --- a/devtools/client/netmonitor/middleware/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DevToolsModules( - 'batching.js', -) diff --git a/devtools/client/netmonitor/moz.build b/devtools/client/netmonitor/moz.build index 107316ebe851..b80c8726a458 100644 --- a/devtools/client/netmonitor/moz.build +++ b/devtools/client/netmonitor/moz.build @@ -6,10 +6,8 @@ DIRS += [ 'actions', 'components', 'har', - 'middleware', 'reducers', - 'selectors', - 'utils', + 'selectors' ] DevToolsModules( @@ -19,8 +17,6 @@ DevToolsModules( 'events.js', 'filter-predicates.js', 'l10n.js', - 'netmonitor-controller.js', - 'netmonitor-view.js', 'panel.js', 'performance-statistics-view.js', 'prefs.js', @@ -31,7 +27,6 @@ DevToolsModules( 'sort-predicates.js', 'store.js', 'toolbar-view.js', - 'waterfall-background.js', ) BROWSER_CHROME_MANIFESTS += ['test/browser.ini'] diff --git a/devtools/client/netmonitor/netmonitor-controller.js b/devtools/client/netmonitor/netmonitor-controller.js index 5017898c9493..2cd595a30d9d 100644 --- a/devtools/client/netmonitor/netmonitor-controller.js +++ b/devtools/client/netmonitor/netmonitor-controller.js @@ -3,10 +3,37 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* eslint-disable mozilla/reject-some-requires */ -/* globals window, NetMonitorView, gStore, dumpn */ +/* globals window, document, NetMonitorView, gStore, Actions */ +/* exported loader */ "use strict"; +var { utils: Cu } = Components; + +// Descriptions for what this frontend is currently doing. +const ACTIVITY_TYPE = { + // Standing by and handling requests normally. + NONE: 0, + + // Forcing the target to reload with cache enabled or disabled. + RELOAD: { + WITH_CACHE_ENABLED: 1, + WITH_CACHE_DISABLED: 2, + WITH_CACHE_DEFAULT: 3 + }, + + // Enabling or disabling the cache without triggering a reload. + ENABLE_CACHE: 3, + DISABLE_CACHE: 4 +}; + +var BrowserLoaderModule = {}; +Cu.import("resource://devtools/client/shared/browser-loader.js", BrowserLoaderModule); +var { loader, require } = BrowserLoaderModule.BrowserLoader({ + baseURI: "resource://devtools/client/netmonitor/", + window +}); + const promise = require("promise"); const Services = require("Services"); const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm"); @@ -14,22 +41,20 @@ const EventEmitter = require("devtools/shared/event-emitter"); const Editor = require("devtools/client/sourceeditor/editor"); const {TimelineFront} = require("devtools/shared/fronts/timeline"); const {Task} = require("devtools/shared/task"); -const { ACTIVITY_TYPE } = require("./constants"); -const { EVENTS } = require("./events"); -const { configureStore } = require("./store"); +const {Prefs} = require("./prefs"); +const {EVENTS} = require("./events"); const Actions = require("./actions/index"); -const { getDisplayedRequestById } = require("./selectors/index"); -const { Prefs } = require("./prefs"); -XPCOMUtils.defineConstant(window, "EVENTS", EVENTS); -XPCOMUtils.defineConstant(window, "ACTIVITY_TYPE", ACTIVITY_TYPE); -XPCOMUtils.defineConstant(window, "Editor", Editor); -XPCOMUtils.defineConstant(window, "Prefs", Prefs); -XPCOMUtils.defineLazyModuleGetter(window, "Chart", +XPCOMUtils.defineConstant(this, "EVENTS", EVENTS); +XPCOMUtils.defineConstant(this, "ACTIVITY_TYPE", ACTIVITY_TYPE); +XPCOMUtils.defineConstant(this, "Editor", Editor); +XPCOMUtils.defineConstant(this, "Prefs", Prefs); + +XPCOMUtils.defineLazyModuleGetter(this, "Chart", "resource://devtools/client/shared/widgets/Chart.jsm"); -// Initialize the global Redux store -window.gStore = configureStore(); +XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper", + "@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper"); /** * Object defining the network monitor controller components. @@ -66,7 +91,6 @@ var NetMonitorController = { } this._shutdown = promise.defer(); { - gStore.dispatch(Actions.batchReset()); NetMonitorView.destroy(); this.TargetEventsHandler.disconnect(); this.NetworkEventsHandler.disconnect(); @@ -263,18 +287,19 @@ var NetMonitorController = { let deferred = promise.defer(); let request = null; let inspector = function () { - request = getDisplayedRequestById(gStore.getState(), requestId); + let predicate = i => i.value === requestId; + request = NetMonitorView.RequestsMenu.getItemForPredicate(predicate); if (!request) { // Reset filters so that the request is visible. gStore.dispatch(Actions.toggleFilterType("all")); - request = getDisplayedRequestById(gStore.getState(), requestId); + request = NetMonitorView.RequestsMenu.getItemForPredicate(predicate); } // If the request was found, select it. Otherwise this function will be // called again once new requests arrive. if (request) { window.off(EVENTS.REQUEST_ADDED, inspector); - gStore.dispatch(Actions.selectRequest(request.id)); + NetMonitorView.RequestsMenu.selectedItem = request; deferred.resolve(); } }; @@ -373,14 +398,14 @@ TargetEventsHandler.prototype = { // Reset UI. if (!Services.prefs.getBoolPref("devtools.webconsole.persistlog")) { NetMonitorView.RequestsMenu.reset(); - } else { - // If the log is persistent, just clear all accumulated timing markers. - gStore.dispatch(Actions.clearTimingMarkers()); + NetMonitorView.Sidebar.toggle(false); } // Switch to the default network traffic inspector view. if (NetMonitorController.getCurrentActivity() == ACTIVITY_TYPE.NONE) { NetMonitorView.showNetworkInspectorView(); } + // Clear any accumulated markers. + NetMonitorController.NetworkEventsHandler.clearMarkers(); window.emit(EVENTS.TARGET_WILL_NAVIGATE); break; @@ -404,6 +429,8 @@ TargetEventsHandler.prototype = { * Functions handling target network events. */ function NetworkEventsHandler() { + this._markers = []; + this._onNetworkEvent = this._onNetworkEvent.bind(this); this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this); this._onDocLoadingMarker = this._onDocLoadingMarker.bind(this); @@ -429,6 +456,19 @@ NetworkEventsHandler.prototype = { return NetMonitorController.timelineFront; }, + get firstDocumentDOMContentLoadedTimestamp() { + let marker = this._markers.filter(e => { + return e.name == "document::DOMContentLoaded"; + })[0]; + + return marker ? marker.unixTime / 1000 : -1; + }, + + get firstDocumentLoadTimestamp() { + let marker = this._markers.filter(e => e.name == "document::Load")[0]; + return marker ? marker.unixTime / 1000 : -1; + }, + /** * Connect to the current target client. */ @@ -485,7 +525,7 @@ NetworkEventsHandler.prototype = { */ _onDocLoadingMarker: function (marker) { window.emit(EVENTS.TIMELINE_EVENT, marker); - gStore.dispatch(Actions.addTimingMarker(marker)); + this._markers.push(marker); }, /** @@ -507,7 +547,8 @@ NetworkEventsHandler.prototype = { } = networkInfo; NetMonitorView.RequestsMenu.addRequest( - actor, {startedDateTime, method, url, isXHR, cause, fromCache, fromServiceWorker} + actor, startedDateTime, method, url, isXHR, cause, fromCache, + fromServiceWorker ); window.emit(EVENTS.NETWORK_EVENT, actor); }, @@ -596,7 +637,7 @@ NetworkEventsHandler.prototype = { _onRequestHeaders: function (response) { NetMonitorView.RequestsMenu.updateRequest(response.from, { requestHeaders: response - }).then(() => { + }, () => { window.emit(EVENTS.RECEIVED_REQUEST_HEADERS, response.from); }); }, @@ -610,7 +651,7 @@ NetworkEventsHandler.prototype = { _onRequestCookies: function (response) { NetMonitorView.RequestsMenu.updateRequest(response.from, { requestCookies: response - }).then(() => { + }, () => { window.emit(EVENTS.RECEIVED_REQUEST_COOKIES, response.from); }); }, @@ -624,7 +665,7 @@ NetworkEventsHandler.prototype = { _onRequestPostData: function (response) { NetMonitorView.RequestsMenu.updateRequest(response.from, { requestPostData: response - }).then(() => { + }, () => { window.emit(EVENTS.RECEIVED_REQUEST_POST_DATA, response.from); }); }, @@ -638,7 +679,7 @@ NetworkEventsHandler.prototype = { _onSecurityInfo: function (response) { NetMonitorView.RequestsMenu.updateRequest(response.from, { securityInfo: response.securityInfo - }).then(() => { + }, () => { window.emit(EVENTS.RECEIVED_SECURITY_INFO, response.from); }); }, @@ -652,7 +693,7 @@ NetworkEventsHandler.prototype = { _onResponseHeaders: function (response) { NetMonitorView.RequestsMenu.updateRequest(response.from, { responseHeaders: response - }).then(() => { + }, () => { window.emit(EVENTS.RECEIVED_RESPONSE_HEADERS, response.from); }); }, @@ -666,7 +707,7 @@ NetworkEventsHandler.prototype = { _onResponseCookies: function (response) { NetMonitorView.RequestsMenu.updateRequest(response.from, { responseCookies: response - }).then(() => { + }, () => { window.emit(EVENTS.RECEIVED_RESPONSE_COOKIES, response.from); }); }, @@ -680,7 +721,7 @@ NetworkEventsHandler.prototype = { _onResponseContent: function (response) { NetMonitorView.RequestsMenu.updateRequest(response.from, { responseContent: response - }).then(() => { + }, () => { window.emit(EVENTS.RECEIVED_RESPONSE_CONTENT, response.from); }); }, @@ -694,11 +735,18 @@ NetworkEventsHandler.prototype = { _onEventTimings: function (response) { NetMonitorView.RequestsMenu.updateRequest(response.from, { eventTimings: response - }).then(() => { + }, () => { window.emit(EVENTS.RECEIVED_EVENT_TIMINGS, response.from); }); }, + /** + * Clears all accumulated markers. + */ + clearMarkers: function () { + this._markers.length = 0; + }, + /** * Fetches the full text of a LongString. * @@ -715,10 +763,19 @@ NetworkEventsHandler.prototype = { } }; +/** + * Returns true if this is document is in RTL mode. + * @return boolean + */ +XPCOMUtils.defineLazyGetter(window, "isRTL", function () { + return window.getComputedStyle(document.documentElement, null) + .direction == "rtl"; +}); + /** * Convenient way of emitting events from the panel window. */ -EventEmitter.decorate(window); +EventEmitter.decorate(this); /** * Preliminary setup for the NetMonitorController object. @@ -738,4 +795,14 @@ Object.defineProperties(window, { } }); -exports.NetMonitorController = NetMonitorController; +/** + * 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-view.js b/devtools/client/netmonitor/netmonitor-view.js index 3009f6aec618..b13b3f91df14 100644 --- a/devtools/client/netmonitor/netmonitor-view.js +++ b/devtools/client/netmonitor/netmonitor-view.js @@ -2,25 +2,25 @@ * 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-globals-from ./netmonitor-controller.js */ /* eslint-disable mozilla/reject-some-requires */ -/* globals $, gStore, NetMonitorController, dumpn */ +/* globals Prefs, setInterval, setTimeout, clearInterval, clearTimeout, btoa */ +/* exported $, $all */ "use strict"; const { testing: isTesting } = require("devtools/shared/flags"); -const promise = require("promise"); -const Editor = require("devtools/client/sourceeditor/editor"); -const { Task } = require("devtools/shared/task"); const { ViewHelpers } = require("devtools/client/shared/widgets/view-helpers"); +const { configureStore } = require("./store"); const { RequestsMenuView } = require("./requests-menu-view"); const { CustomRequestView } = require("./custom-request-view"); const { ToolbarView } = require("./toolbar-view"); const { SidebarView } = require("./sidebar-view"); const { DetailsView } = require("./details-view"); const { PerformanceStatisticsView } = require("./performance-statistics-view"); -const { ACTIVITY_TYPE } = require("./constants"); -const Actions = require("./actions/index"); -const { Prefs } = require("./prefs"); + +// Initialize the global redux variables +var gStore = configureStore(); // ms const WDA_DEFAULT_VERIFY_INTERVAL = 50; @@ -80,6 +80,12 @@ var NetMonitorView = { this._detailsPane.setAttribute("width", Prefs.networkDetailsWidth); this._detailsPane.setAttribute("height", Prefs.networkDetailsHeight); this.toggleDetailsPane({ visible: false }); + + // Disable the performance statistics mode. + if (!Prefs.statistics) { + $("#request-menu-context-perf").hidden = true; + $("#notice-perf-message").hidden = true; + } }, /** @@ -163,6 +169,7 @@ var NetMonitorView = { */ showNetworkInspectorView: function () { this._body.selectedPanel = $("#network-inspector-view"); + this.RequestsMenu._flushWaterfallViews(true); }, /** @@ -185,7 +192,7 @@ var NetMonitorView = { // • The response content size and request total time are necessary for // populating the statistics view. // • The response mime type is used for categorization. - yield whenDataAvailable(requestsView.store, [ + yield whenDataAvailable(requestsView, [ "responseHeaders", "status", "contentSize", "mimeType", "totalTime" ]); } catch (ex) { @@ -193,9 +200,8 @@ var NetMonitorView = { console.error(ex); } - const requests = requestsView.store.getState().requests.requests; - statisticsView.createPrimedCacheChart(requests); - statisticsView.createEmptyCacheChart(requests); + statisticsView.createPrimedCacheChart(requestsView.items); + statisticsView.createEmptyCacheChart(requestsView.items); }); }, @@ -235,39 +241,44 @@ var NetMonitorView = { _editorPromises: new Map() }; +/** + * 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); + /** * Makes sure certain properties are available on all objects in a data store. * - * @param Store dataStore - * A Redux store for which to check the availability of properties. + * @param array dataStore + * The request view object from which to fetch the item list. * @param array mandatoryFields * A list of strings representing properties of objects in dataStore. * @return object * A promise resolved when all objects in dataStore contain the * properties defined in mandatoryFields. */ -function whenDataAvailable(dataStore, mandatoryFields) { - return new Promise((resolve, reject) => { - let interval = setInterval(() => { - const { requests } = dataStore.getState().requests; - const allFieldsPresent = !requests.isEmpty() && requests.every( - item => mandatoryFields.every( - field => item.get(field) !== undefined - ) - ); +function whenDataAvailable(requestsView, mandatoryFields) { + let deferred = promise.defer(); - if (allFieldsPresent) { - clearInterval(interval); - clearTimeout(timer); - resolve(); - } - }, WDA_DEFAULT_VERIFY_INTERVAL); - - let timer = setTimeout(() => { + let interval = setInterval(() => { + const { attachments } = requestsView; + if (attachments.length > 0 && attachments.every(item => { + return mandatoryFields.every(field => field in item); + })) { clearInterval(interval); - reject(new Error("Timed out while waiting for data")); - }, WDA_DEFAULT_GIVE_UP_TIMEOUT); - }); + clearTimeout(timer); + deferred.resolve(); + } + }, WDA_DEFAULT_VERIFY_INTERVAL); + + let timer = setTimeout(() => { + clearInterval(interval); + deferred.reject(new Error("Timed out while waiting for data")); + }, WDA_DEFAULT_GIVE_UP_TIMEOUT); + + return deferred.promise; } /** @@ -279,5 +290,3 @@ NetMonitorView.NetworkDetails = new DetailsView(); NetMonitorView.RequestsMenu = new RequestsMenuView(); NetMonitorView.CustomRequest = new CustomRequestView(); NetMonitorView.PerformanceStatistics = new PerformanceStatisticsView(); - -exports.NetMonitorView = NetMonitorView; diff --git a/devtools/client/netmonitor/netmonitor.js b/devtools/client/netmonitor/netmonitor.js deleted file mode 100644 index 5c23b5c52657..000000000000 --- a/devtools/client/netmonitor/netmonitor.js +++ /dev/null @@ -1,60 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* globals window, document, NetMonitorController, NetMonitorView */ -/* exported Netmonitor, NetMonitorController, NetMonitorView, $, $all, dumpn */ - -"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) { - const { require } = BrowserLoader({ - baseURI: "resource://devtools/client/netmonitor/", - window, - commonLibRequire: toolbox.browserRequire, - }); - - window.windowRequire = require; - - const { NetMonitorController } = require("./netmonitor-controller.js"); - const { NetMonitorView } = require("./netmonitor-view.js"); - - window.NetMonitorController = NetMonitorController; - window.NetMonitorView = NetMonitorView; - - NetMonitorController._toolbox = toolbox; - NetMonitorController._target = toolbox.target; -} - -Netmonitor.prototype = { - init() { - return window.NetMonitorController.startupNetMonitor(); - }, - - destroy() { - 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 c1dbb4b67bac..69e2e1d3100d 100644 --- a/devtools/client/netmonitor/netmonitor.xul +++ b/devtools/client/netmonitor/netmonitor.xul @@ -12,7 +12,8 @@