/* 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, createElement, } = require("resource://devtools/client/shared/vendor/react.mjs"); const { render, unmountComponentAtNode, } = require("resource://devtools/client/shared/vendor/react-dom.mjs"); const Provider = require("resource://devtools/client/shared/vendor/react-redux.js").Provider; const ToolboxProvider = require("resource://devtools/client/framework/store-provider.js"); const { visibilityHandlerStore, } = require("resource://devtools/client/shared/redux/visibilityHandlerStore.js"); const { START_IGNORE_ACTION, } = require("resource://devtools/client/shared/redux/middleware/ignore.js"); const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js"); const App = require("resource://devtools/client/netmonitor/src/components/App.js"); const { FluentL10n, } = require("resource://devtools/client/shared/fluent-l10n/fluent-l10n.js"); const LocalizationProvider = createFactory(FluentReact.LocalizationProvider); const { EVENTS, } = require("resource://devtools/client/netmonitor/src/constants.js"); const { getDisplayedRequestById, } = require("resource://devtools/client/netmonitor/src/selectors/index.js"); const SearchDispatcher = require("resource://devtools/client/netmonitor/src/workers/search/index.js"); /** * Global App object for Network panel. This object depends * on the UI and can't be created independently. * * This object can be consumed by other panels (e.g. Console * is using inspectRequest). */ class NetMonitorApp { /** * @param {object} api An existing API object to be reused. */ constructor(api) { this.api = api; } async bootstrap({ toolbox, document }) { // Get the root element for mounting. this.mount = document.querySelector("#mount"); const openLink = link => { const parentDoc = toolbox.doc; const iframe = parentDoc.getElementById( "toolbox-panel-iframe-netmonitor" ); const { top } = iframe.ownerDocument.defaultView; top.openWebLinkIn(link, "tab"); }; const openSplitConsole = err => { toolbox.openSplitConsole().then(() => { toolbox.target.logErrorInPage(err, "har"); }); }; const { actions, connector, store } = this.api; const sourceMapURLService = toolbox.sourceMapURLService; const fluentL10n = new FluentL10n(); await fluentL10n.init(["devtools/client/netmonitor.ftl"]); // Render the root Application component. render( createElement( Provider, // Also wrap the store in order to pause store update notifications while the panel is hidden. // (this can't be done from create-store as it is loaded from the toolbox, without the browser loader // and isn't bound to the netmonitor document) { store: visibilityHandlerStore(store) }, LocalizationProvider( { bundles: fluentL10n.getBundles() }, createElement( ToolboxProvider, { store: toolbox.store }, createElement(App, { actions, connector, openLink, openSplitConsole, sourceMapURLService, toolboxDoc: toolbox.doc, }) ) ) ), this.mount ); } /** * Clean up (unmount from DOM, remove listeners, disconnect). */ destroy() { unmountComponentAtNode(this.mount); SearchDispatcher.stop(); // Make sure to destroy the API object. It's usually destroyed // in the Toolbox destroy method, but we need it here for case // where the Network panel is initialized without the toolbox // and running in a tab (see initialize.js for details). this.api.destroy(); // Prevents any further action from being dispatched this.api.store.dispatch(START_IGNORE_ACTION); } /** * 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. */ async inspectRequest(requestId) { const { actions, store } = this.api; // 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; const 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) { this.api.off(EVENTS.REQUEST_ADDED, inspector); actions.selectRequest(request.id); resolve(); } }; inspector(); if (!request) { this.api.on(EVENTS.REQUEST_ADDED, inspector); } }); } } exports.NetMonitorApp = NetMonitorApp;