forked from mirrors/gecko-dev
MozReview-Commit-ID: IMu1sJLxQYy --HG-- extra : rebase_source : aa5a6f1a67ad0d4d83bcb0308d3dd6fe0de0ee0f
289 lines
9 KiB
JavaScript
289 lines
9 KiB
JavaScript
/* 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/. */
|
|
|
|
/* import-globals-from ./netmonitor-controller.js */
|
|
/* eslint-disable mozilla/reject-some-requires */
|
|
/* globals Prefs, setInterval, setTimeout, clearInterval, clearTimeout, btoa */
|
|
/* exported $, $all */
|
|
|
|
"use strict";
|
|
|
|
const { testing: isTesting } = require("devtools/shared/flags");
|
|
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");
|
|
var {Prefs} = require("./prefs");
|
|
|
|
// Initialize the global redux variables
|
|
var gStore = configureStore();
|
|
|
|
// ms
|
|
const WDA_DEFAULT_VERIFY_INTERVAL = 50;
|
|
|
|
// Use longer timeout during testing as the tests need this process to succeed
|
|
// and two seconds is quite short on slow debug builds. The timeout here should
|
|
// be at least equal to the general mochitest timeout of 45 seconds so that this
|
|
// never gets hit during testing.
|
|
// ms
|
|
const WDA_DEFAULT_GIVE_UP_TIMEOUT = isTesting ? 45000 : 2000;
|
|
|
|
const DEFAULT_EDITOR_CONFIG = {
|
|
mode: Editor.modes.text,
|
|
readOnly: true,
|
|
lineNumbers: true
|
|
};
|
|
|
|
/**
|
|
* Object defining the network monitor view components.
|
|
*/
|
|
var NetMonitorView = {
|
|
/**
|
|
* Initializes the network monitor view.
|
|
*/
|
|
initialize: function () {
|
|
this._initializePanes();
|
|
|
|
this.Toolbar.initialize(gStore);
|
|
this.RequestsMenu.initialize(gStore);
|
|
this.NetworkDetails.initialize();
|
|
this.CustomRequest.initialize();
|
|
this.PerformanceStatistics.initialize(gStore);
|
|
},
|
|
|
|
/**
|
|
* Destroys the network monitor view.
|
|
*/
|
|
destroy: function () {
|
|
this._isDestroyed = true;
|
|
this.Toolbar.destroy();
|
|
this.RequestsMenu.destroy();
|
|
this.NetworkDetails.destroy();
|
|
this.CustomRequest.destroy();
|
|
|
|
this._destroyPanes();
|
|
},
|
|
|
|
/**
|
|
* Initializes the UI for all the displayed panes.
|
|
*/
|
|
_initializePanes: function () {
|
|
dumpn("Initializing the NetMonitorView panes");
|
|
|
|
this._body = $("#body");
|
|
this._detailsPane = $("#details-pane");
|
|
|
|
this._detailsPane.setAttribute("width", Prefs.networkDetailsWidth);
|
|
this._detailsPane.setAttribute("height", Prefs.networkDetailsHeight);
|
|
this.toggleDetailsPane({ visible: false });
|
|
},
|
|
|
|
/**
|
|
* Destroys the UI for all the displayed panes.
|
|
*/
|
|
_destroyPanes: Task.async(function* () {
|
|
dumpn("Destroying the NetMonitorView panes");
|
|
|
|
Prefs.networkDetailsWidth = this._detailsPane.getAttribute("width");
|
|
Prefs.networkDetailsHeight = this._detailsPane.getAttribute("height");
|
|
|
|
this._detailsPane = null;
|
|
|
|
for (let p of this._editorPromises.values()) {
|
|
let editor = yield p;
|
|
editor.destroy();
|
|
}
|
|
}),
|
|
|
|
/**
|
|
* Gets the visibility state of the network details pane.
|
|
* @return boolean
|
|
*/
|
|
get detailsPaneHidden() {
|
|
return this._detailsPane.classList.contains("pane-collapsed");
|
|
},
|
|
|
|
/**
|
|
* Sets the network details pane hidden or visible.
|
|
*
|
|
* @param object flags
|
|
* An object containing some of the following properties:
|
|
* - visible: true if the pane should be shown, false to hide
|
|
* - animated: true to display an animation on toggle
|
|
* - delayed: true to wait a few cycles before toggle
|
|
* - callback: a function to invoke when the toggle finishes
|
|
* @param number tabIndex [optional]
|
|
* The index of the intended selected tab in the details pane.
|
|
*/
|
|
toggleDetailsPane: function (flags, tabIndex) {
|
|
ViewHelpers.togglePane(flags, this._detailsPane);
|
|
|
|
if (flags.visible) {
|
|
this._body.classList.remove("pane-collapsed");
|
|
gStore.dispatch(Actions.openSidebar(true));
|
|
} else {
|
|
this._body.classList.add("pane-collapsed");
|
|
gStore.dispatch(Actions.openSidebar(false));
|
|
}
|
|
|
|
if (tabIndex !== undefined) {
|
|
$("#event-details-pane").selectedIndex = tabIndex;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Gets the current mode for this tool.
|
|
* @return string (e.g, "network-inspector-view" or "network-statistics-view")
|
|
*/
|
|
get currentFrontendMode() {
|
|
// The getter may be called from a timeout after the panel is destroyed.
|
|
if (!this._body.selectedPanel) {
|
|
return null;
|
|
}
|
|
return this._body.selectedPanel.id;
|
|
},
|
|
|
|
/**
|
|
* Toggles between the frontend view modes ("Inspector" vs. "Statistics").
|
|
*/
|
|
toggleFrontendMode: function () {
|
|
if (this.currentFrontendMode != "network-inspector-view") {
|
|
this.showNetworkInspectorView();
|
|
} else {
|
|
this.showNetworkStatisticsView();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Switches to the "Inspector" frontend view mode.
|
|
*/
|
|
showNetworkInspectorView: function () {
|
|
this._body.selectedPanel = $("#network-inspector-view");
|
|
},
|
|
|
|
/**
|
|
* Switches to the "Statistics" frontend view mode.
|
|
*/
|
|
showNetworkStatisticsView: function () {
|
|
this._body.selectedPanel = $("#network-statistics-view");
|
|
|
|
let controller = NetMonitorController;
|
|
let requestsView = this.RequestsMenu;
|
|
let statisticsView = this.PerformanceStatistics;
|
|
|
|
Task.spawn(function* () {
|
|
statisticsView.displayPlaceholderCharts();
|
|
yield controller.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
|
|
|
|
try {
|
|
// • The response headers and status code are required for determining
|
|
// whether a response is "fresh" (cacheable).
|
|
// • 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, [
|
|
"responseHeaders", "status", "contentSize", "mimeType", "totalTime"
|
|
]);
|
|
} catch (ex) {
|
|
// Timed out while waiting for data. Continue with what we have.
|
|
console.error(ex);
|
|
}
|
|
|
|
const requests = requestsView.store.getState().requests.requests;
|
|
statisticsView.createPrimedCacheChart(requests);
|
|
statisticsView.createEmptyCacheChart(requests);
|
|
});
|
|
},
|
|
|
|
reloadPage: function () {
|
|
NetMonitorController.triggerActivity(
|
|
ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT);
|
|
},
|
|
|
|
/**
|
|
* Lazily initializes and returns a promise for a Editor instance.
|
|
*
|
|
* @param string id
|
|
* The id of the editor placeholder node.
|
|
* @return object
|
|
* A promise that is resolved when the editor is available.
|
|
*/
|
|
editor: function (id) {
|
|
dumpn("Getting a NetMonitorView editor: " + id);
|
|
|
|
if (this._editorPromises.has(id)) {
|
|
return this._editorPromises.get(id);
|
|
}
|
|
|
|
let deferred = promise.defer();
|
|
this._editorPromises.set(id, deferred.promise);
|
|
|
|
// Initialize the source editor and store the newly created instance
|
|
// in the ether of a resolved promise's value.
|
|
let editor = new Editor(DEFAULT_EDITOR_CONFIG);
|
|
editor.appendTo($(id)).then(() => deferred.resolve(editor));
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
_body: null,
|
|
_detailsPane: null,
|
|
_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 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
|
|
)
|
|
);
|
|
|
|
if (allFieldsPresent) {
|
|
clearInterval(interval);
|
|
clearTimeout(timer);
|
|
resolve();
|
|
}
|
|
}, WDA_DEFAULT_VERIFY_INTERVAL);
|
|
|
|
let timer = setTimeout(() => {
|
|
clearInterval(interval);
|
|
reject(new Error("Timed out while waiting for data"));
|
|
}, WDA_DEFAULT_GIVE_UP_TIMEOUT);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Preliminary setup for the NetMonitorView object.
|
|
*/
|
|
NetMonitorView.Toolbar = new ToolbarView();
|
|
NetMonitorView.Sidebar = new SidebarView();
|
|
NetMonitorView.NetworkDetails = new DetailsView();
|
|
NetMonitorView.RequestsMenu = new RequestsMenuView();
|
|
NetMonitorView.CustomRequest = new CustomRequestView();
|
|
NetMonitorView.PerformanceStatistics = new PerformanceStatisticsView();
|