app.js (5532B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { 8 createFactory, 9 createElement, 10 } = require("resource://devtools/client/shared/vendor/react.mjs"); 11 const { 12 render, 13 unmountComponentAtNode, 14 } = require("resource://devtools/client/shared/vendor/react-dom.mjs"); 15 const Provider = 16 require("resource://devtools/client/shared/vendor/react-redux.js").Provider; 17 const ToolboxProvider = require("resource://devtools/client/framework/store-provider.js"); 18 const { 19 visibilityHandlerStore, 20 } = require("resource://devtools/client/shared/redux/visibilityHandlerStore.js"); 21 const { 22 START_IGNORE_ACTION, 23 } = require("resource://devtools/client/shared/redux/middleware/ignore.js"); 24 25 const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js"); 26 const App = require("resource://devtools/client/netmonitor/src/components/App.js"); 27 const { 28 FluentL10n, 29 } = require("resource://devtools/client/shared/fluent-l10n/fluent-l10n.js"); 30 const LocalizationProvider = createFactory(FluentReact.LocalizationProvider); 31 const { 32 EVENTS, 33 } = require("resource://devtools/client/netmonitor/src/constants.js"); 34 35 const { 36 getDisplayedRequestById, 37 } = require("resource://devtools/client/netmonitor/src/selectors/index.js"); 38 39 const SearchDispatcher = require("resource://devtools/client/netmonitor/src/workers/search/index.js"); 40 41 /** 42 * Global App object for Network panel. This object depends 43 * on the UI and can't be created independently. 44 * 45 * This object can be consumed by other panels (e.g. Console 46 * is using inspectRequest), by the Launchpad (bootstrap), etc. 47 */ 48 class NetMonitorApp { 49 /** 50 * @param {object} api An existing API object to be reused. 51 */ 52 constructor(api) { 53 this.api = api; 54 } 55 56 async bootstrap({ toolbox, document }) { 57 // Get the root element for mounting. 58 this.mount = document.querySelector("#mount"); 59 60 const openLink = link => { 61 const parentDoc = toolbox.doc; 62 const iframe = parentDoc.getElementById( 63 "toolbox-panel-iframe-netmonitor" 64 ); 65 const { top } = iframe.ownerDocument.defaultView; 66 top.openWebLinkIn(link, "tab"); 67 }; 68 69 const openSplitConsole = err => { 70 toolbox.openSplitConsole().then(() => { 71 toolbox.target.logErrorInPage(err, "har"); 72 }); 73 }; 74 75 const { actions, connector, store } = this.api; 76 77 const sourceMapURLService = toolbox.sourceMapURLService; 78 79 const fluentL10n = new FluentL10n(); 80 await fluentL10n.init(["devtools/client/netmonitor.ftl"]); 81 82 // Render the root Application component. 83 render( 84 createElement( 85 Provider, 86 // Also wrap the store in order to pause store update notifications while the panel is hidden. 87 // (this can't be done from create-store as it is loaded from the toolbox, without the browser loader 88 // and isn't bound to the netmonitor document) 89 { store: visibilityHandlerStore(store) }, 90 LocalizationProvider( 91 { bundles: fluentL10n.getBundles() }, 92 createElement( 93 ToolboxProvider, 94 { store: toolbox.store }, 95 createElement(App, { 96 actions, 97 connector, 98 openLink, 99 openSplitConsole, 100 sourceMapURLService, 101 toolboxDoc: toolbox.doc, 102 }) 103 ) 104 ) 105 ), 106 this.mount 107 ); 108 } 109 110 /** 111 * Clean up (unmount from DOM, remove listeners, disconnect). 112 */ 113 destroy() { 114 unmountComponentAtNode(this.mount); 115 116 SearchDispatcher.stop(); 117 118 // Make sure to destroy the API object. It's usually destroyed 119 // in the Toolbox destroy method, but we need it here for case 120 // where the Network panel is initialized without the toolbox 121 // and running in a tab (see initialize.js for details). 122 this.api.destroy(); 123 124 // Prevents any further action from being dispatched 125 this.api.store.dispatch(START_IGNORE_ACTION); 126 } 127 128 /** 129 * Selects the specified request in the waterfall and opens the details view. 130 * This is a firefox toolbox specific API, which providing an ability to inspect 131 * a network request directly from other internal toolbox panel. 132 * 133 * @param {string} requestId The actor ID of the request to inspect. 134 * @return {object} A promise resolved once the task finishes. 135 */ 136 async inspectRequest(requestId) { 137 const { actions, store } = this.api; 138 139 // Look for the request in the existing ones or wait for it to appear, 140 // if the network monitor is still loading. 141 return new Promise(resolve => { 142 let request = null; 143 const inspector = () => { 144 request = getDisplayedRequestById(store.getState(), requestId); 145 if (!request) { 146 // Reset filters so that the request is visible. 147 actions.toggleRequestFilterType("all"); 148 request = getDisplayedRequestById(store.getState(), requestId); 149 } 150 151 // If the request was found, select it. Otherwise this function will be 152 // called again once new requests arrive. 153 if (request) { 154 this.api.off(EVENTS.REQUEST_ADDED, inspector); 155 actions.selectRequest(request.id); 156 resolve(); 157 } 158 }; 159 160 inspector(); 161 162 if (!request) { 163 this.api.on(EVENTS.REQUEST_ADDED, inspector); 164 } 165 }); 166 } 167 } 168 169 exports.NetMonitorApp = NetMonitorApp;