fune/devtools/client/netmonitor/netmonitor-view.js
Jarda Snajdr bcce5eb099 Bug 1309866 - Migrate RequestsMenuView to a React component with Redux store r=Honza
MozReview-Commit-ID: IMu1sJLxQYy

--HG--
extra : rebase_source : aa5a6f1a67ad0d4d83bcb0308d3dd6fe0de0ee0f
2016-10-11 15:13:28 +02:00

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();