--- a/devtools/client/netmonitor/index.html
+++ b/devtools/client/netmonitor/index.html
@@ -9,36 +9,45 @@
<link rel="stylesheet" href="chrome://devtools/content/netmonitor/src/assets/styles/netmonitor.css"/>
<script src="chrome://devtools/content/shared/theme-switching.js"></script>
</head>
<body class="theme-body" role="application">
<div id="mount"></div>
<script>
"use strict";
- const { BrowserLoader } = Components.utils.import("resource://devtools/client/shared/browser-loader.js", {});
+ const { BrowserLoader } = Components.utils.import(
+ "resource://devtools/client/shared/browser-loader.js", {});
const require = window.windowRequire = BrowserLoader({
baseURI: "resource://devtools/client/netmonitor/",
window,
}).require;
const EventEmitter = require("devtools/shared/old-event-emitter");
const { createFactory } = require("devtools/client/shared/vendor/react");
const { render, unmountComponentAtNode } = require("devtools/client/shared/vendor/react-dom");
const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
const { bindActionCreators } = require("devtools/client/shared/vendor/redux");
+ const { Connector } = require("./src/connector/index");
const { configureStore } = require("./src/utils/create-store");
- const store = configureStore();
- const actions = bindActionCreators(require("./src/actions/index"), store.dispatch);
- const { onFirefoxConnect, onDisconnect } = require("./src/connector/index");
+ const App = createFactory(require("./src/components/app"));
+ const { getDisplayedRequestById } = require("./src/selectors/index");
+ const { EVENTS } = require("./src/constants");
// Inject EventEmitter into global window.
EventEmitter.decorate(window);
+
+ // Configure store/state object.
+ let connector = new Connector();
+ const store = configureStore(connector);
+ const actions = bindActionCreators(require("./src/actions/index"), store.dispatch);
+
// Inject to global window for testing
window.store = store;
+ window.connector = connector;
window.Netmonitor = {
bootstrap({ toolbox }) {
this.mount = document.querySelector("#mount");
const connection = {
tabConnection: {
tabTarget: toolbox.target,
@@ -48,27 +57,67 @@
const openLink = (link) => {
let parentDoc = toolbox.doc;
let iframe = parentDoc.getElementById("toolbox-panel-iframe-netmonitor");
let top = iframe.ownerDocument.defaultView.top;
top.openUILinkIn(link, "tab");
};
- const App = createFactory(require("./src/components/app"));
+ // Render the root Application component.
const sourceMapService = toolbox.sourceMapURLService;
- const app = App({ sourceMapService, openLink });
+ const app = App({ connector, openLink, sourceMapService });
render(Provider({ store }, app), this.mount);
- return onFirefoxConnect(connection, actions, store.getState);
+
+ // Connect to the Firefox backend by default.
+ return connector.connectFirefox(connection, actions, store.getState);
},
destroy() {
unmountComponentAtNode(this.mount);
- return onDisconnect();
+ return connector.disconnect();
},
+
+ /**
+ * Selects the specified request in the waterfall and opens the details view.
+ * This is a firefox toolbox specific API, which providing an ability to inspect
+ * a network request directly from other internal toolbox panel.
+ *
+ * @param {string} requestId The actor ID of the request to inspect.
+ * @return {object} A promise resolved once the task finishes.
+ */
+ inspectRequest(requestId) {
+ // Look for the request in the existing ones or wait for it to appear, if
+ // the network monitor is still loading.
+ return new Promise((resolve) => {
+ let request = null;
+ let inspector = () => {
+ request = getDisplayedRequestById(store.getState(), requestId);
+ if (!request) {
+ // Reset filters so that the request is visible.
+ actions.toggleRequestFilterType("all");
+ request = getDisplayedRequestById(store.getState(), requestId);
+ }
+
+ // 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);
+ actions.selectRequest(request.id);
+ resolve();
+ }
+ };
+
+ inspector();
+
+ if (!request) {
+ window.on(EVENTS.REQUEST_ADDED, inspector);
+ }
+ });
+ }
};
// Implement support for:
// chrome://devtools/content/netmonitor/index.html?type=tab&id=1234 URLs
// where 1234 is the tab id, you can retrieve from about:debugging#tabs links.
// Simply copy the id from about:devtools-toolbox?type=tab&id=1234 URLs.
// URL constructor doesn't support chrome: scheme
--- a/devtools/client/netmonitor/index.js
+++ b/devtools/client/netmonitor/index.js
@@ -8,17 +8,16 @@
* This script is the entry point of devtools-launchpad. Make netmonitor possible
* to run on standalone browser tab without chrome privilege.
* See README.md for more information.
*/
const React = require("react");
const ReactDOM = require("react-dom");
const { bindActionCreators } = require("redux");
const { bootstrap, renderRoot } = require("devtools-launchpad");
-const EventEmitter = require("devtools-modules/src/utils/event-emitter");
const { Services: { appinfo, pref }} = require("devtools-modules");
// Initialize preferences as early as possible
pref("devtools.theme", "light");
pref("devtools.cache.disabled", false);
pref("devtools.netmonitor.enabled", true);
pref("devtools.netmonitor.filters", "[\"all\"]");
pref("devtools.netmonitor.visibleColumns",
@@ -34,25 +33,27 @@ pref("devtools.netmonitor.har.jsonpCallb
pref("devtools.netmonitor.har.includeResponseBodies", true);
pref("devtools.netmonitor.har.compress", false);
pref("devtools.netmonitor.har.forceExport", false);
pref("devtools.netmonitor.har.pageLoadedTimeout", 1500);
pref("devtools.netmonitor.har.enableAutoExportToFile", false);
pref("devtools.netmonitor.persistlog", false);
pref("devtools.styleeditor.enabled", true);
-const { configureStore } = require("./src/utils/create-store");
-
require("./src/assets/styles/netmonitor.css");
+const EventEmitter = require("devtools-modules/src/utils/event-emitter");
EventEmitter.decorate(window);
+
+const { configureStore } = require("./src/utils/create-store");
const App = require("./src/components/app");
-const store = configureStore();
+const { Connector } = require("./src/connector/index");
+const connector = new Connector();
+const store = configureStore(connector);
const actions = bindActionCreators(require("./src/actions"), store.dispatch);
-const { onConnect } = require("./src/connector");
// Inject to global window for testing
window.store = store;
/**
* Stylesheet links in devtools xhtml files are using chrome or resource URLs.
* Rewrite the href attribute to remove the protocol. web-server.js contains redirects
* to map CSS urls to the proper file. Supports urls using:
@@ -75,11 +76,12 @@ window.addEventListener("DOMContentLoade
document.documentElement.setAttribute("platform", "win");
}
});
bootstrap(React, ReactDOM).then((connection) => {
if (!connection) {
return;
}
- renderRoot(React, ReactDOM, App, store);
- onConnect(connection, actions, store.getState);
+
+ renderRoot(React, ReactDOM, App, store, {connector});
+ connector.connect(connection, actions, store.getState);
});
--- a/devtools/client/netmonitor/src/actions/requests.js
+++ b/devtools/client/netmonitor/src/actions/requests.js
@@ -1,15 +1,14 @@
/* 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 { sendHTTPRequest } = require("../connector/index");
const {
ADD_REQUEST,
CLEAR_REQUESTS,
CLONE_SELECTED_REQUEST,
REMOVE_SELECTED_CUSTOM_REQUEST,
SEND_CUSTOM_REQUEST,
TOGGLE_RECORDING,
UPDATE_REQUEST,
@@ -42,17 +41,17 @@ function cloneSelectedRequest() {
return {
type: CLONE_SELECTED_REQUEST
};
}
/**
* Send a new HTTP request using the data in the custom request form.
*/
-function sendCustomRequest() {
+function sendCustomRequest(connector) {
return (dispatch, getState) => {
const selected = getSelectedRequest(getState());
if (!selected) {
return;
}
// Send a new HTTP request using the data in the custom request form
@@ -63,17 +62,17 @@ function sendCustomRequest() {
};
if (selected.requestHeaders) {
data.headers = selected.requestHeaders.headers;
}
if (selected.requestPostData) {
data.body = selected.requestPostData.postData.text;
}
- sendHTTPRequest(data, (response) => {
+ connector.sendHTTPRequest(data, (response) => {
return dispatch({
type: SEND_CUSTOM_REQUEST,
id: response.eventActor.actor,
});
});
};
}
--- a/devtools/client/netmonitor/src/actions/ui.js
+++ b/devtools/client/netmonitor/src/actions/ui.js
@@ -10,17 +10,16 @@ const {
ENABLE_PERSISTENT_LOGS,
DISABLE_BROWSER_CACHE,
OPEN_STATISTICS,
RESET_COLUMNS,
SELECT_DETAILS_PANEL_TAB,
TOGGLE_COLUMN,
WATERFALL_RESIZE,
} = require("../constants");
-const { triggerActivity } = require("../connector/index");
/**
* Change network details panel.
*
* @param {boolean} open - expected network details panel open state
*/
function openNetworkDetails(open) {
return {
@@ -51,21 +50,22 @@ function disableBrowserCache(disabled) {
type: DISABLE_BROWSER_CACHE,
disabled,
};
}
/**
* Change performance statistics panel open state.
*
+ * @param {Object} connector - connector object to the backend
* @param {boolean} visible - expected performance statistics panel open state
*/
-function openStatistics(open) {
+function openStatistics(connector, open) {
if (open) {
- triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
+ connector.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
}
return {
type: OPEN_STATISTICS,
open,
};
}
/**
@@ -134,19 +134,19 @@ function togglePersistentLogs() {
function toggleBrowserCache() {
return (dispatch, getState) =>
dispatch(disableBrowserCache(!getState().ui.browserCacheDisabled));
}
/**
* Toggle performance statistics panel.
*/
-function toggleStatistics() {
+function toggleStatistics(connector) {
return (dispatch, getState) =>
- dispatch(openStatistics(!getState().ui.statisticsOpen));
+ dispatch(openStatistics(connector, !getState().ui.statisticsOpen));
}
module.exports = {
openNetworkDetails,
enablePersistentLogs,
disableBrowserCache,
openStatistics,
resetColumns,
--- a/devtools/client/netmonitor/src/components/app.js
+++ b/devtools/client/netmonitor/src/components/app.js
@@ -12,36 +12,47 @@ const {
const { connect } = require("devtools/client/shared/vendor/react-redux");
// Components
const MonitorPanel = createFactory(require("./monitor-panel"));
const StatisticsPanel = createFactory(require("./statistics-panel"));
const { div } = DOM;
-/*
+/**
* App component
* The top level component for representing main panel
*/
function App({
+ connector,
openLink,
sourceMapService,
statisticsOpen,
}) {
return (
div({ className: "network-monitor" },
- !statisticsOpen ? MonitorPanel({ openLink, sourceMapService }) : StatisticsPanel()
+ !statisticsOpen ? MonitorPanel({
+ connector,
+ sourceMapService,
+ openLink,
+ }) : StatisticsPanel({
+ connector
+ })
)
);
}
App.displayName = "App";
App.propTypes = {
+ // The backend connector object.
+ connector: PropTypes.object.isRequired,
+ // Callback for opening links in the UI
openLink: PropTypes.func,
// Service to enable the source map feature.
sourceMapService: PropTypes.object,
+ // True if the stats panel is opened.
statisticsOpen: PropTypes.bool.isRequired,
};
module.exports = connect(
(state) => ({ statisticsOpen: state.ui.statisticsOpen }),
)(App);
--- a/devtools/client/netmonitor/src/components/custom-request-panel.js
+++ b/devtools/client/netmonitor/src/components/custom-request-panel.js
@@ -143,16 +143,17 @@ function CustomRequestPanel({
),
)
);
}
CustomRequestPanel.displayName = "CustomRequestPanel";
CustomRequestPanel.propTypes = {
+ connector: PropTypes.object.isRequired,
removeSelectedCustomRequest: PropTypes.func.isRequired,
request: PropTypes.object,
sendCustomRequest: PropTypes.func.isRequired,
updateRequest: PropTypes.func.isRequired,
};
/**
* Parse a text representation of a name[divider]value list with
@@ -244,14 +245,14 @@ function updateCustomRequestFields(evt,
if (data) {
// All updateRequest batch mode should be disabled to make UI editing in sync
updateRequest(request.id, data, false);
}
}
module.exports = connect(
(state) => ({ request: getSelectedRequest(state) }),
- (dispatch) => ({
+ (dispatch, props) => ({
removeSelectedCustomRequest: () => dispatch(Actions.removeSelectedCustomRequest()),
- sendCustomRequest: () => dispatch(Actions.sendCustomRequest()),
+ sendCustomRequest: () => dispatch(Actions.sendCustomRequest(props.connector)),
updateRequest: (id, data, batch) => dispatch(Actions.updateRequest(id, data, batch)),
})
)(CustomRequestPanel);
--- a/devtools/client/netmonitor/src/components/monitor-panel.js
+++ b/devtools/client/netmonitor/src/components/monitor-panel.js
@@ -9,41 +9,40 @@ 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 { getLongString } = require("../connector/index");
const { getFormDataSections } = require("../utils/request-utils");
const { getSelectedRequest } = require("../selectors/index");
// Components
const SplitBox = createFactory(require("devtools/client/shared/components/splitter/SplitBox"));
const NetworkDetailsPanel = createFactory(require("./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: {
+ connector: PropTypes.object.isRequired,
isEmpty: PropTypes.bool.isRequired,
networkDetailsOpen: PropTypes.bool.isRequired,
openNetworkDetails: PropTypes.func.isRequired,
request: PropTypes.object,
- // Service to enable the source map feature.
sourceMapService: PropTypes.object,
openLink: PropTypes.func,
updateRequest: PropTypes.func.isRequired,
},
getInitialState() {
return {
isVerticalSpliter: MediaQueryList.matches,
@@ -67,17 +66,17 @@ const MonitorPanel = createClass({
} = request;
if (!formDataSections && requestHeaders &&
requestHeadersFromUploadStream && requestPostData) {
getFormDataSections(
requestHeaders,
requestHeadersFromUploadStream,
requestPostData,
- getLongString,
+ this.props.connector.getLongString,
).then((newFormDataSections) => {
updateRequest(
request.id,
{ formDataSections: newFormDataSections },
true,
);
});
}
@@ -101,16 +100,17 @@ const MonitorPanel = createClass({
onLayoutChange() {
this.setState({
isVerticalSpliter: MediaQueryList.matches,
});
},
render() {
let {
+ connector,
isEmpty,
networkDetailsOpen,
sourceMapService,
openLink
} = this.props;
let initialWidth = Services.prefs.getIntPref(
"devtools.netmonitor.panes-network-details-width");
@@ -121,19 +121,20 @@ const MonitorPanel = createClass({
Toolbar(),
SplitBox({
className: "devtools-responsive-container",
initialWidth: `${initialWidth}px`,
initialHeight: `${initialHeight}px`,
minSize: "50px",
maxSize: "80%",
splitterSize: "1px",
- startPanel: RequestList({ isEmpty }),
+ startPanel: RequestList({ isEmpty, connector }),
endPanel: networkDetailsOpen && NetworkDetailsPanel({
ref: "endPanel",
+ connector,
sourceMapService,
openLink,
}),
endPanelCollapsed: !networkDetailsOpen,
endPanelControl: true,
vert: this.state.isVerticalSpliter,
}),
)
--- a/devtools/client/netmonitor/src/components/network-details-panel.js
+++ b/devtools/client/netmonitor/src/components/network-details-panel.js
@@ -14,20 +14,21 @@ const Actions = require("../actions/inde
const { getSelectedRequest } = require("../selectors/index");
// Components
const CustomRequestPanel = createFactory(require("./custom-request-panel"));
const TabboxPanel = createFactory(require("./tabbox-panel"));
const { div } = DOM;
-/*
+/**
* Network details panel component
*/
function NetworkDetailsPanel({
+ connector,
activeTabId,
cloneSelectedRequest,
request,
selectTab,
sourceMapService,
openLink,
}) {
if (!request) {
@@ -35,37 +36,39 @@ function NetworkDetailsPanel({
}
return (
div({ className: "network-details-panel" },
!request.isCustom ?
TabboxPanel({
activeTabId,
cloneSelectedRequest,
+ connector,
+ openLink,
request,
selectTab,
sourceMapService,
- openLink,
}) :
CustomRequestPanel({
+ connector,
request,
})
)
);
}
NetworkDetailsPanel.displayName = "NetworkDetailsPanel";
NetworkDetailsPanel.propTypes = {
+ connector: PropTypes.object.isRequired,
activeTabId: PropTypes.string,
cloneSelectedRequest: PropTypes.func.isRequired,
open: PropTypes.bool,
request: PropTypes.object,
selectTab: PropTypes.func.isRequired,
- // Service to enable the source map feature.
sourceMapService: PropTypes.object,
openLink: PropTypes.func,
};
module.exports = connect(
(state) => ({
activeTabId: state.ui.detailsPanelSelectedTab,
request: getSelectedRequest(state),
--- a/devtools/client/netmonitor/src/components/request-list-content.js
+++ b/devtools/client/netmonitor/src/components/request-list-content.js
@@ -30,36 +30,39 @@ const REQUESTS_TOOLTIP_TOGGLE_DELAY = 50
/**
* Renders the actual contents of the request list.
*/
const RequestListContent = createClass({
displayName: "RequestListContent",
propTypes: {
+ connector: PropTypes.object.isRequired,
columns: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
displayedRequests: PropTypes.object.isRequired,
firstRequestStartedMillis: PropTypes.number.isRequired,
fromCache: PropTypes.bool,
onCauseBadgeMouseDown: PropTypes.func.isRequired,
onItemMouseDown: PropTypes.func.isRequired,
onSecurityIconMouseDown: PropTypes.func.isRequired,
onSelectDelta: PropTypes.func.isRequired,
onThumbnailMouseDown: PropTypes.func.isRequired,
onWaterfallMouseDown: PropTypes.func.isRequired,
scale: PropTypes.number,
selectedRequestId: PropTypes.string,
},
componentWillMount() {
- const { dispatch } = this.props;
+ const { dispatch, connector } = this.props;
this.contextMenu = new RequestListContextMenu({
cloneSelectedRequest: () => dispatch(Actions.cloneSelectedRequest()),
- openStatistics: (open) => dispatch(Actions.openStatistics(open)),
+ getTabTarget: connector.getTabTarget,
+ getLongString: connector.getLongString,
+ openStatistics: (open) => dispatch(Actions.openStatistics(connector, open)),
});
this.tooltip = new HTMLTooltip(window.parent.document, { type: "arrow" });
},
componentDidMount() {
// Set the CSS variables for waterfall scaling
this.setScalingStyles();
@@ -151,18 +154,19 @@ const RequestListContent = createClass({
if (!itemId) {
return false;
}
let requestItem = this.props.displayedRequests.find(r => r.id == itemId);
if (!requestItem) {
return false;
}
+ let { connector } = this.props;
if (requestItem.responseContent && target.closest(".requests-list-icon")) {
- return setTooltipImageContent(tooltip, itemEl, requestItem);
+ return setTooltipImageContent(connector, tooltip, itemEl, requestItem);
}
return false;
},
/**
* Scroll listener for the requests menu view.
*/
--- a/devtools/client/netmonitor/src/components/request-list-empty-notice.js
+++ b/devtools/client/netmonitor/src/components/request-list-empty-notice.js
@@ -7,17 +7,16 @@
const {
createClass,
createFactory,
DOM,
PropTypes,
} = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const Actions = require("../actions/index");
-const { triggerActivity } = require("../connector/index");
const { ACTIVITY_TYPE } = require("../constants");
const { L10N } = require("../utils/l10n");
const { getPerformanceAnalysisURL } = require("../utils/mdn-utils");
// Components
const MDNLink = createFactory(require("./mdn-link"));
const { button, div, span } = DOM;
@@ -32,16 +31,17 @@ const PERFORMANCE_NOTICE_3 = L10N.getStr
/**
* 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: {
+ connector: PropTypes.object.isRequired,
onReloadClick: PropTypes.func.isRequired,
onPerfClick: PropTypes.func.isRequired,
},
render() {
return div(
{
className: "request-list-empty-notice",
@@ -70,13 +70,14 @@ const RequestListEmptyNotice = createCla
MDNLink({ url: getPerformanceAnalysisURL() })
)
);
}
});
module.exports = connect(
undefined,
- dispatch => ({
- onPerfClick: () => dispatch(Actions.openStatistics(true)),
- onReloadClick: () => triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT),
+ (dispatch, props) => ({
+ onPerfClick: () => dispatch(Actions.openStatistics(props.connector, true)),
+ onReloadClick: () => props.connector.triggerActivity(
+ ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT),
})
)(RequestListEmptyNotice);
--- a/devtools/client/netmonitor/src/components/request-list.js
+++ b/devtools/client/netmonitor/src/components/request-list.js
@@ -16,25 +16,29 @@ const RequestListEmptyNotice = createFac
const RequestListHeader = createFactory(require("./request-list-header"));
const StatusBar = createFactory(require("./status-bar"));
const { div } = DOM;
/**
* Request panel component
*/
-function RequestList({ isEmpty }) {
+function RequestList({
+ connector,
+ isEmpty,
+}) {
return (
div({ className: "request-list-container" },
RequestListHeader(),
- isEmpty ? RequestListEmptyNotice() : RequestListContent(),
- StatusBar(),
+ isEmpty ? RequestListEmptyNotice({connector}) : RequestListContent({connector}),
+ StatusBar({connector}),
)
);
}
RequestList.displayName = "RequestList";
RequestList.propTypes = {
+ connector: PropTypes.object.isRequired,
isEmpty: PropTypes.bool.isRequired,
};
module.exports = RequestList;
--- a/devtools/client/netmonitor/src/components/stack-trace-panel.js
+++ b/devtools/client/netmonitor/src/components/stack-trace-panel.js
@@ -4,44 +4,50 @@
"use strict";
const {
createFactory,
DOM,
PropTypes,
} = require("devtools/client/shared/vendor/react");
-const { viewSourceInDebugger } = require("../connector/index");
const { div } = DOM;
// Components
const StackTrace = createFactory(require("devtools/client/shared/components/StackTrace"));
+/**
+ * This component represents a side panel responsible for
+ * rendering stack-trace info for selected request.
+ */
function StackTracePanel({
+ connector,
openLink,
request,
sourceMapService,
}) {
let { stacktrace } = request.cause;
return (
div({ className: "panel-container" },
StackTrace({
stacktrace,
- onViewSourceInDebugger: ({ url, line }) => viewSourceInDebugger(url, line),
+ onViewSourceInDebugger: ({ url, line }) => {
+ return connector.viewSourceInDebugger(url, line);
+ },
sourceMapService,
openLink,
}),
)
);
}
StackTracePanel.displayName = "StackTracePanel";
StackTracePanel.propTypes = {
+ connector: PropTypes.object.isRequired,
request: PropTypes.object.isRequired,
- // Service to enable the source map feature.
sourceMapService: PropTypes.object,
openLink: PropTypes.func,
};
module.exports = StackTracePanel;
--- a/devtools/client/netmonitor/src/components/statistics-panel.js
+++ b/devtools/client/netmonitor/src/components/statistics-panel.js
@@ -39,16 +39,17 @@ const CHARTS_CACHE_DISABLED = L10N.getSt
* Statistics panel component
* Performance analysis tool which shows you how long the browser takes to
* download the different parts of your site.
*/
const StatisticsPanel = createClass({
displayName: "StatisticsPanel",
propTypes: {
+ connector: PropTypes.object.isRequired,
closeStatistics: PropTypes.func.isRequired,
enableRequestFilterTypeOnly: PropTypes.func.isRequired,
requests: PropTypes.object,
},
getInitialState() {
return {
isVerticalSpliter: MediaQueryList.matches,
@@ -297,14 +298,14 @@ const StatisticsPanel = createClass({
);
}
});
module.exports = connect(
(state) => ({
requests: state.requests.requests.valueSeq(),
}),
- (dispatch) => ({
- closeStatistics: () => dispatch(Actions.openStatistics(false)),
+ (dispatch, props) => ({
+ closeStatistics: () => dispatch(Actions.openStatistics(props.connector, false)),
enableRequestFilterTypeOnly: (label) =>
dispatch(Actions.enableRequestFilterTypeOnly(label)),
})
)(StatisticsPanel);
--- a/devtools/client/netmonitor/src/components/status-bar.js
+++ b/devtools/client/netmonitor/src/components/status-bar.js
@@ -83,26 +83,27 @@ function StatusBar({ summary, openStatis
}, `load: ${getFormattedTime(load)}`),
)
);
}
StatusBar.displayName = "StatusBar";
StatusBar.propTypes = {
+ connector: PropTypes.object.isRequired,
openStatistics: PropTypes.func.isRequired,
summary: PropTypes.object.isRequired,
timingMarkers: PropTypes.object.isRequired,
};
module.exports = connect(
(state) => ({
summary: getDisplayedRequestsSummary(state),
timingMarkers: {
DOMContentLoaded:
getDisplayedTimingMarker(state, "firstDocumentDOMContentLoadedTimestamp"),
load: getDisplayedTimingMarker(state, "firstDocumentLoadTimestamp"),
},
}),
- (dispatch) => ({
- openStatistics: () => dispatch(Actions.openStatistics(true)),
+ (dispatch, props) => ({
+ openStatistics: () => dispatch(Actions.openStatistics(props.connector, true)),
}),
)(StatusBar);
--- a/devtools/client/netmonitor/src/components/tabbox-panel.js
+++ b/devtools/client/netmonitor/src/components/tabbox-panel.js
@@ -26,27 +26,28 @@ const TimingsPanel = createFactory(requi
const COOKIES_TITLE = L10N.getStr("netmonitor.tab.cookies");
const HEADERS_TITLE = L10N.getStr("netmonitor.tab.headers");
const PARAMS_TITLE = L10N.getStr("netmonitor.tab.params");
const RESPONSE_TITLE = L10N.getStr("netmonitor.tab.response");
const SECURITY_TITLE = L10N.getStr("netmonitor.tab.security");
const STACK_TRACE_TITLE = L10N.getStr("netmonitor.tab.stackTrace");
const TIMINGS_TITLE = L10N.getStr("netmonitor.tab.timings");
-/*
+/**
* Tabbox panel component
* Display the network request details
*/
function TabboxPanel({
activeTabId,
- cloneSelectedRequest = ()=>{},
+ cloneSelectedRequest = () => {},
+ connector,
+ openLink,
request,
selectTab,
sourceMapService,
- openLink,
}) {
if (!request) {
return null;
}
return (
Tabbar({
activeTabId,
@@ -85,17 +86,17 @@ function TabboxPanel({
},
TimingsPanel({ request }),
),
request.cause && request.cause.stacktrace && request.cause.stacktrace.length > 0 &&
TabPanel({
id: PANELS.STACK_TRACE,
title: STACK_TRACE_TITLE,
},
- StackTracePanel({ request, sourceMapService, openLink }),
+ StackTracePanel({ request, sourceMapService, openLink, connector }),
),
request.securityState && request.securityState !== "insecure" &&
TabPanel({
id: PANELS.SECURITY,
title: SECURITY_TITLE,
},
SecurityPanel({ request, openLink }),
),
@@ -103,16 +104,16 @@ function TabboxPanel({
);
}
TabboxPanel.displayName = "TabboxPanel";
TabboxPanel.propTypes = {
activeTabId: PropTypes.string,
cloneSelectedRequest: PropTypes.func,
+ connector: PropTypes.object.isRequired,
+ openLink: PropTypes.func,
request: PropTypes.object,
selectTab: PropTypes.func.isRequired,
- // Service to enable the source map feature.
sourceMapService: PropTypes.object,
- openLink: PropTypes.func,
};
module.exports = connect()(TabboxPanel);
--- a/devtools/client/netmonitor/src/connector/chrome-connector.js
+++ b/devtools/client/netmonitor/src/connector/chrome-connector.js
@@ -30,16 +30,24 @@ class ChromeConnector {
this.connector.setup(tabConnection, this.actions);
this.connector.willNavigate(this.willNavigate);
}
async disconnect() {
this.connector.disconnect();
}
+ pause() {
+ this.disconnect();
+ }
+
+ resume() {
+ this.setup();
+ }
+
/**
* currently all events are about "navigation" is not support on CDP
*/
willNavigate() {
this.actions.batchReset();
this.actions.clearRequests();
}
--- a/devtools/client/netmonitor/src/connector/firefox-connector.js
+++ b/devtools/client/netmonitor/src/connector/firefox-connector.js
@@ -2,31 +2,29 @@
* 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 Services = require("Services");
const { TimelineFront } = require("devtools/shared/fronts/timeline");
const { ACTIVITY_TYPE, EVENTS } = require("../constants");
-const { getDisplayedRequestById } = require("../selectors/index");
const FirefoxDataProvider = require("./firefox-data-provider");
class FirefoxConnector {
constructor() {
// Public methods
this.connect = this.connect.bind(this);
this.disconnect = this.disconnect.bind(this);
this.willNavigate = this.willNavigate.bind(this);
this.displayCachedEvents = this.displayCachedEvents.bind(this);
this.onDocLoadingMarker = this.onDocLoadingMarker.bind(this);
this.sendHTTPRequest = this.sendHTTPRequest.bind(this);
this.setPreferences = this.setPreferences.bind(this);
this.triggerActivity = this.triggerActivity.bind(this);
- this.inspectRequest = this.inspectRequest.bind(this);
this.getTabTarget = this.getTabTarget.bind(this);
this.viewSourceInDebugger = this.viewSourceInDebugger.bind(this);
// Internals
this.getLongString = this.getLongString.bind(this);
this.getNetworkRequest = this.getNetworkRequest.bind(this);
}
@@ -38,22 +36,17 @@ class FirefoxConnector {
this.webConsoleClient = this.tabTarget.activeConsole;
this.dataProvider = new FirefoxDataProvider({
webConsoleClient: this.webConsoleClient,
actions: this.actions,
});
- this.tabTarget.on("will-navigate", this.willNavigate);
- this.tabTarget.on("close", this.disconnect);
- this.webConsoleClient.on("networkEvent",
- this.dataProvider.onNetworkEvent);
- this.webConsoleClient.on("networkEventUpdate",
- this.dataProvider.onNetworkEventUpdate);
+ this.addListeners();
// Don't start up waiting for timeline markers if the server isn't
// recent enough to emit the markers we're interested in.
if (this.tabTarget.getTrait("documentLoadingMarkers")) {
this.timelineFront = new TimelineFront(this.tabTarget.client, this.tabTarget.form);
this.timelineFront.on("doc-loading", this.onDocLoadingMarker);
await this.timelineFront.start({ withDocLoadingEvents: true });
}
@@ -66,26 +59,48 @@ class FirefoxConnector {
// The timeline front wasn't initialized and started if the server wasn't
// recent enough to emit the markers we were interested in.
if (this.tabTarget.getTrait("documentLoadingMarkers") && this.timelineFront) {
this.timelineFront.off("doc-loading", this.onDocLoadingMarker);
await this.timelineFront.destroy();
}
- this.tabTarget.off("will-navigate");
- this.tabTarget.off("close");
+ this.removeListeners();
+
this.tabTarget = null;
- this.webConsoleClient.off("networkEvent");
- this.webConsoleClient.off("networkEventUpdate");
this.webConsoleClient = null;
this.timelineFront = null;
this.dataProvider = null;
}
+ pause() {
+ this.removeListeners();
+ }
+
+ resume() {
+ this.addListeners();
+ }
+
+ addListeners() {
+ this.tabTarget.on("will-navigate", this.willNavigate);
+ this.tabTarget.on("close", this.disconnect);
+ this.webConsoleClient.on("networkEvent",
+ this.dataProvider.onNetworkEvent);
+ this.webConsoleClient.on("networkEventUpdate",
+ this.dataProvider.onNetworkEventUpdate);
+ }
+
+ removeListeners() {
+ this.tabTarget.off("will-navigate");
+ this.tabTarget.off("close");
+ this.webConsoleClient.off("networkEvent");
+ this.webConsoleClient.off("networkEventUpdate");
+ }
+
willNavigate() {
if (!Services.prefs.getBoolPref("devtools.netmonitor.persistlog")) {
this.actions.batchReset();
this.actions.clearRequests();
} else {
// If the log is persistent, just clear all accumulated timing markers.
this.actions.clearTimingMarkers();
}
@@ -210,52 +225,16 @@ class FirefoxConnector {
performReload: false,
}).then(standBy);
}
this.currentActivity = ACTIVITY_TYPE.NONE;
return Promise.reject(new Error("Invalid activity type"));
}
/**
- * Selects the specified request in the waterfall and opens the details view.
- *
- * @param {string} requestId The actor ID of the request to inspect.
- * @return {object} A promise resolved once the task finishes.
- */
- inspectRequest(requestId) {
- // Look for the request in the existing ones or wait for it to appear, if
- // the network monitor is still loading.
- return new Promise((resolve) => {
- let request = null;
- let inspector = () => {
- request = getDisplayedRequestById(this.getState(), requestId);
- if (!request) {
- // Reset filters so that the request is visible.
- this.actions.toggleRequestFilterType("all");
- request = getDisplayedRequestById(this.getState(), requestId);
- }
-
- // 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);
- this.actions.selectRequest(request.id);
- resolve();
- }
- };
-
- inspector();
-
- if (!request) {
- window.on(EVENTS.REQUEST_ADDED, inspector);
- }
- });
- }
-
- /**
* Fetches the network information packet from actor server
*
* @param {string} id request id
* @return {object} networkInfo data packet
*/
getNetworkRequest(id) {
return this.dataProvider.getNetworkRequest(id);
}
--- a/devtools/client/netmonitor/src/connector/index.js
+++ b/devtools/client/netmonitor/src/connector/index.js
@@ -1,85 +1,103 @@
/* 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";
-let connector = {};
+
+/**
+ * Generic connector wrapper object that is responsible for
+ * instantiating specific connector implementation according
+ * to the client type.
+ */
+class Connector {
+ constructor() {
+ this.connector = null;
-function onConnect(connection, actions, getState) {
- if (!connection || !connection.tab) {
- return;
+ // Bind public API
+ this.connect = this.connect.bind(this);
+ this.disconnect = this.disconnect.bind(this);
+ this.connectChrome = this.connectChrome.bind(this);
+ this.connectFirefox = this.connectFirefox.bind(this);
+ this.getLongString = this.getLongString.bind(this);
+ this.getNetworkRequest = this.getNetworkRequest.bind(this);
+ this.getTabTarget = this.getTabTarget.bind(this);
+ this.sendHTTPRequest = this.sendHTTPRequest.bind(this);
+ this.setPreferences = this.setPreferences.bind(this);
+ this.triggerActivity = this.triggerActivity.bind(this);
+ this.viewSourceInDebugger = this.viewSourceInDebugger.bind(this);
+ }
+
+ // Connect/Disconnect API
+
+ connect(connection, actions, getState) {
+ if (!connection || !connection.tab) {
+ return;
+ }
+
+ let { clientType } = connection.tab;
+ switch (clientType) {
+ case "chrome":
+ this.connectChrome(connection, actions, getState);
+ break;
+ case "firefox":
+ this.connectFirefox(connection, actions, getState);
+ break;
+ default:
+ throw Error(`Unknown client type - ${clientType}`);
+ }
}
- let { clientType } = connection.tab;
- switch (clientType) {
- case "chrome":
- onChromeConnect(connection, actions, getState);
- break;
- case "firefox":
- onFirefoxConnect(connection, actions, getState);
- break;
- default:
- throw Error(`Unknown client type - ${clientType}`);
+ disconnect() {
+ this.connector && this.connector.disconnect();
+ }
+
+ connectChrome(connection, actions, getState) {
+ this.connector = require("./chrome-connector");
+ this.connector.connect(connection, actions, getState);
+ }
+
+ connectFirefox(connection, actions, getState) {
+ this.connector = require("./firefox-connector");
+ this.connector.connect(connection, actions, getState);
+ }
+
+ pause() {
+ this.connector.pause();
+ }
+
+ resume() {
+ this.connector.resume();
+ }
+
+ // Public API
+
+ getLongString() {
+ return this.connector.getLongString(...arguments);
+ }
+
+ getNetworkRequest() {
+ return this.connector.getNetworkRequest(...arguments);
+ }
+
+ getTabTarget() {
+ return this.connector.getTabTarget();
+ }
+
+ sendHTTPRequest() {
+ return this.connector.sendHTTPRequest(...arguments);
+ }
+
+ setPreferences() {
+ return this.connector.setPreferences(...arguments);
+ }
+
+ triggerActivity() {
+ return this.connector.triggerActivity(...arguments);
+ }
+
+ viewSourceInDebugger() {
+ return this.connector.viewSourceInDebugger(...arguments);
}
}
-function onDisconnect() {
- connector && connector.disconnect();
-}
-
-function onChromeConnect(connection, actions, getState) {
- connector = require("./chrome-connector");
- connector.connect(connection, actions, getState);
-}
-
-function onFirefoxConnect(connection, actions, getState) {
- connector = require("./firefox-connector");
- connector.connect(connection, actions, getState);
-}
-
-function inspectRequest() {
- return connector.inspectRequest(...arguments);
-}
-
-function getLongString() {
- return connector.getLongString(...arguments);
-}
-
-function getNetworkRequest() {
- return connector.getNetworkRequest(...arguments);
-}
-
-function getTabTarget() {
- return connector.getTabTarget();
-}
-
-function sendHTTPRequest() {
- return connector.sendHTTPRequest(...arguments);
-}
-
-function setPreferences() {
- return connector.setPreferences(...arguments);
-}
-
-function triggerActivity() {
- return connector.triggerActivity(...arguments);
-}
-
-function viewSourceInDebugger() {
- return connector.viewSourceInDebugger(...arguments);
-}
-
-module.exports = {
- onConnect,
- onChromeConnect,
- onFirefoxConnect,
- onDisconnect,
- getLongString,
- getNetworkRequest,
- getTabTarget,
- inspectRequest,
- sendHTTPRequest,
- setPreferences,
- triggerActivity,
- viewSourceInDebugger,
-};
+module.exports.Connector = Connector;
--- a/devtools/client/netmonitor/src/har/test/browser_net_har_throttle_upload.js
+++ b/devtools/client/netmonitor/src/har/test/browser_net_har_throttle_upload.js
@@ -11,20 +11,19 @@ add_task(function* () {
});
function* throttleUploadTest(actuallyThrottle) {
let { tab, monitor } = yield initNetMonitor(
HAR_EXAMPLE_URL + "html_har_post-data-test-page.html");
info("Starting test... (actuallyThrottle = " + actuallyThrottle + ")");
- let { store, windowRequire } = monitor.panelWin;
+ let { connector, store, windowRequire } = monitor.panelWin;
let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
- let { setPreferences } =
- windowRequire("devtools/client/netmonitor/src/connector/index");
+ let setPreferences = () => connector.setPreferences;
let RequestListContextMenu = windowRequire(
"devtools/client/netmonitor/src/request-list-context-menu");
store.dispatch(Actions.batchEnable(false));
const size = 4096;
const uploadSize = actuallyThrottle ? size / 3 : 0;
--- a/devtools/client/netmonitor/src/middleware/recording.js
+++ b/devtools/client/netmonitor/src/middleware/recording.js
@@ -3,22 +3,39 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
TOGGLE_RECORDING,
} = require("../constants");
+const {
+ getRecordingState,
+} = require("../selectors/index");
+
/**
* Start/stop HTTP traffic recording.
+ *
+ * The UI state of the toolbar toggle button is stored in UI
+ * reducer and the backend connection is managed here in the
+ * middleware.
*/
-function recordingMiddleware(store) {
- return next => action => {
+function recordingMiddleware(connector) {
+ return store => next => action => {
const res = next(action);
+
+ // Pause/resume HTTP monitoring according to
+ // the user action.
if (action.type === TOGGLE_RECORDING) {
- // TODO connect/disconnect the backend.
+ let recording = getRecordingState(store.getState());
+ if (recording) {
+ connector.resume();
+ } else {
+ connector.pause();
+ }
}
+
return res;
};
}
module.exports = recordingMiddleware;
--- a/devtools/client/netmonitor/src/request-list-context-menu.js
+++ b/devtools/client/netmonitor/src/request-list-context-menu.js
@@ -6,36 +6,36 @@
const Services = require("Services");
const { Curl } = require("devtools/client/shared/curl");
const { gDevTools } = require("devtools/client/framework/devtools");
const { saveAs } = require("devtools/client/shared/file-saver");
const { copyString } = require("devtools/shared/platform/clipboard");
const { HarExporter } = require("./har/har-exporter");
const {
- getLongString,
- getTabTarget,
-} = require("./connector/index");
-const {
getSelectedRequest,
getSortedRequests,
} = require("./selectors/index");
const { L10N } = require("./utils/l10n");
const { showMenu } = require("devtools/client/netmonitor/src/utils/menu");
const {
getUrlQuery,
parseQueryString,
getUrlBaseName,
} = require("./utils/request-utils");
function RequestListContextMenu({
cloneSelectedRequest,
+ getLongString,
+ getTabTarget,
openStatistics,
}) {
this.cloneSelectedRequest = cloneSelectedRequest;
+ this.getLongString = getLongString;
+ this.getTabTarget = getTabTarget;
this.openStatistics = openStatistics;
}
RequestListContextMenu.prototype = {
get selectedRequest() {
// FIXME: Bug 1336382 - Implement RequestListContextMenu React component
// Remove window.store
return getSelectedRequest(window.store.getState());
@@ -234,25 +234,25 @@ RequestListContextMenu.prototype = {
let win = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
win.openUILinkIn(this.selectedRequest.url, "tab", { relatedToCurrent: true });
},
/**
* Opens selected item in the debugger
*/
openInDebugger() {
- let toolbox = gDevTools.getToolbox(getTabTarget());
+ let toolbox = gDevTools.getToolbox(this.getTabTarget());
toolbox.viewSourceInDebugger(this.selectedRequest.url, 0);
},
/**
* Opens selected item in the style editor
*/
openInStyleEditor() {
- let toolbox = gDevTools.getToolbox(getTabTarget());
+ let toolbox = gDevTools.getToolbox(this.getTabTarget());
toolbox.viewSourceInStyleEditor(this.selectedRequest.url, 0);
},
/**
* Copy the request url from the currently selected item.
*/
copyUrl() {
copyString(this.selectedRequest.url);
@@ -382,20 +382,20 @@ RequestListContextMenu.prototype = {
// FIXME: This will not work in launchpad
// document.execCommand(‘cut’/‘copy’) was denied because it was not called from
// inside a short running user-generated event handler.
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard
return HarExporter.save(this.getDefaultHarOptions());
},
getDefaultHarOptions() {
- let form = getTabTarget().form;
+ let form = this.getTabTarget().form;
let title = form.title || form.url;
return {
- getString: getLongString,
+ getString: this.getLongString,
items: this.sortedRequests,
title: title
};
}
};
module.exports = RequestListContextMenu;
--- a/devtools/client/netmonitor/src/request-list-tooltip.js
+++ b/devtools/client/netmonitor/src/request-list-tooltip.js
@@ -3,29 +3,28 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
setImageTooltip,
getImageDimensions,
} = require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper");
-const { getLongString } = require("./connector/index");
const { formDataURI } = require("./utils/request-utils");
const REQUESTS_TOOLTIP_IMAGE_MAX_DIM = 400; // px
-async function setTooltipImageContent(tooltip, itemEl, requestItem) {
+async function setTooltipImageContent(connector, tooltip, itemEl, requestItem) {
let { mimeType, text, encoding } = requestItem.responseContent.content;
if (!mimeType || !mimeType.includes("image/")) {
return false;
}
- let string = await getLongString(text);
+ let string = await connector.getLongString(text);
let src = formDataURI(mimeType, encoding, string);
let maxDim = REQUESTS_TOOLTIP_IMAGE_MAX_DIM;
let { naturalWidth, naturalHeight } = await getImageDimensions(tooltip.doc, src);
let options = { maxDim, naturalWidth, naturalHeight };
setImageTooltip(tooltip, tooltip.doc, src, options);
return itemEl.querySelector(".requests-list-icon");
}
--- a/devtools/client/netmonitor/src/utils/create-store.js
+++ b/devtools/client/netmonitor/src/utils/create-store.js
@@ -1,58 +1,90 @@
/* 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 Services = require("Services");
const { applyMiddleware, createStore } = require("devtools/client/shared/vendor/redux");
+
+// Middleware
const batching = require("../middleware/batching");
const prefs = require("../middleware/prefs");
const thunk = require("../middleware/thunk");
+const recording = require("../middleware/recording");
+
+// Reducers
const rootReducer = require("../reducers/index");
const { FilterTypes, Filters } = require("../reducers/filters");
const { Requests } = require("../reducers/requests");
const { Sort } = require("../reducers/sort");
const { TimingMarkers } = require("../reducers/timing-markers");
const { UI, Columns } = require("../reducers/ui");
-function configureStore() {
- const getPref = (pref) => {
- try {
- return JSON.parse(Services.prefs.getCharPref(pref));
- } catch (_) {
- return [];
- }
+/**
+ * Configure state and middleware for the Network monitor tool.
+ */
+function configureStore(connector) {
+ // Prepare initial state.
+ const initialState = {
+ filters: new Filters({
+ requestFilterTypes: getFilterState()
+ }),
+ requests: new Requests(),
+ sort: new Sort(),
+ timingMarkers: new TimingMarkers(),
+ ui: new UI({
+ columns: getColumnState()
+ }),
};
- let activeFilters = {};
- let filters = getPref("devtools.netmonitor.filters");
- filters.forEach((filter) => {
- activeFilters[filter] = true;
- });
+ // Prepare middleware.
+ let middleware = applyMiddleware(
+ thunk,
+ prefs,
+ batching,
+ recording(connector)
+ );
+ return createStore(rootReducer, initialState, middleware);
+}
+
+// Helpers
+
+/**
+ * Get column state from preferences.
+ */
+function getColumnState() {
let columns = new Columns();
let visibleColumns = getPref("devtools.netmonitor.visibleColumns");
for (let [col] of columns) {
columns = columns.withMutations((state) => {
state.set(col, visibleColumns.includes(col));
});
}
- const initialState = {
- filters: new Filters({
- requestFilterTypes: new FilterTypes(activeFilters)
- }),
- requests: new Requests(),
- sort: new Sort(),
- timingMarkers: new TimingMarkers(),
- ui: new UI({
- columns,
- }),
- };
+ return columns;
+}
- return createStore(rootReducer, initialState, applyMiddleware(thunk, prefs, batching));
+/**
+ * Get filter state from preferences.
+ */
+function getFilterState() {
+ let activeFilters = {};
+ let filters = getPref("devtools.netmonitor.filters");
+ filters.forEach((filter) => {
+ activeFilters[filter] = true;
+ });
+ return new FilterTypes(activeFilters);
+}
+
+function getPref(pref) {
+ try {
+ return JSON.parse(Services.prefs.getCharPref(pref));
+ } catch (_) {
+ return [];
+ }
}
exports.configureStore = configureStore;
--- a/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
+++ b/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
@@ -134,19 +134,17 @@ NewConsoleOutputWrapper.prototype = {
frame.line
),
onViewSourceInStyleEditor: frame => this.toolbox.viewSourceInStyleEditor(
frame.url,
frame.line
),
openNetworkPanel: (requestId) => {
return this.toolbox.selectTool("netmonitor").then((panel) => {
- let { inspectRequest } = panel.panelWin.windowRequire(
- "devtools/client/netmonitor/src/connector/index");
- return inspectRequest(requestId);
+ return panel.panelWin.Netmonitor.inspectRequest(requestId);
});
},
sourceMapService: this.toolbox ? this.toolbox.sourceMapURLService : null,
highlightDomElement: (grip, options = {}) => {
return this.toolbox.highlighterUtils
? this.toolbox.highlighterUtils.highlightDomValueGrip(grip, options)
: null;
},
--- a/devtools/client/webconsole/webconsole.js
+++ b/devtools/client/webconsole/webconsole.js
@@ -1844,24 +1844,21 @@ WebConsoleFrame.prototype = {
* Opens the network monitor and highlights the specified request.
*
* @param string requestId
* The actor ID of the network request.
*/
openNetworkPanel: function (requestId) {
let toolbox = gDevTools.getToolbox(this.owner.target);
// The browser console doesn't have a toolbox.
- if (!toolbox) {
- return;
+ if (toolbox) {
+ return toolbox.selectTool("netmonitor").then(panel => {
+ return panel.panelWin.Netmonitor.inspectRequest(requestId);
+ });
}
- return toolbox.selectTool("netmonitor").then(panel => {
- let { inspectRequest } = panel.panelWin.windowRequire(
- "devtools/client/netmonitor/src/connector/index");
- return inspectRequest(requestId);
- });
},
/**
* Handler for page location changes.
*
* @param string uri
* New page location.
* @param string title