mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-06 20:11:38 +08:00
When a user toggles off and then on the network monitoring, without the Preserve Log option enabled, the network log resets. However, if the individual request inspection pane is open, it will stay open. This is due to a parameter in NetworkLogView#_reset being true instead of false. However, correcting this behavior has a side effect that, when enabling the logging option in the same manner as above but with the keyboard, it shifts focus to the network data grid (which is empty). This causes an a11y problem because NVDA just announces "blank". So this change removes the call to NetworkLogView#resetFocus from the handler within NetworkPanel#_hideRequestFocus(). However, that change ALSO causes a problem, in that pressing <Esc> uses that code path. Instead, we'll call NetworkLogView#resetFocus from the keyboard handler which is the NetworkPanel action delegate. Bug: 1025332 Change-Id: Ida7b78447237914df5f51b31edc7ab8cf2aa7c56 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/1918734 Reviewed-by: Mike Jackson <mjackson@microsoft.com> Reviewed-by: Brandon Goddard <brgoddar@microsoft.com> Commit-Queue: Robert Paveza <Rob.Paveza@microsoft.com>
865 lines
29 KiB
JavaScript
865 lines
29 KiB
JavaScript
/*
|
|
* Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
|
|
* Copyright (C) 2008, 2009 Anthony Ricaud <rik@webkit.org>
|
|
* Copyright (C) 2011 Google Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
|
* its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
/**
|
|
* @implements {UI.ContextMenu.Provider}
|
|
* @implements {UI.ViewLocationResolver}
|
|
*/
|
|
Network.NetworkPanel = class extends UI.Panel {
|
|
constructor() {
|
|
super('network');
|
|
this.registerRequiredCSS('network/networkPanel.css');
|
|
|
|
this._networkLogShowOverviewSetting = Common.settings.createSetting('networkLogShowOverview', true);
|
|
this._networkLogLargeRowsSetting = Common.settings.createSetting('networkLogLargeRows', false);
|
|
this._networkRecordFilmStripSetting = Common.settings.createSetting('networkRecordFilmStripSetting', false);
|
|
this._toggleRecordAction = /** @type {!UI.Action }*/ (UI.actionRegistry.action('network.toggle-recording'));
|
|
|
|
/** @type {number|undefined} */
|
|
this._pendingStopTimer;
|
|
/** @type {?Network.NetworkItemView} */
|
|
this._networkItemView = null;
|
|
/** @type {?PerfUI.FilmStripView} */
|
|
this._filmStripView = null;
|
|
/** @type {?Network.NetworkPanel.FilmStripRecorder} */
|
|
this._filmStripRecorder = null;
|
|
/** @type {?SDK.NetworkRequest} */
|
|
this._currentRequest = null;
|
|
|
|
const panel = new UI.VBox();
|
|
|
|
const networkToolbarContainer = panel.contentElement.createChild('div', 'network-toolbar-container');
|
|
this._panelToolbar = new UI.Toolbar('', networkToolbarContainer);
|
|
this._rightToolbar = new UI.Toolbar('', networkToolbarContainer);
|
|
|
|
this._filterBar = new UI.FilterBar('networkPanel', true);
|
|
this._filterBar.show(panel.contentElement);
|
|
|
|
this._settingsPane = new UI.HBox();
|
|
this._settingsPane.element.classList.add('network-settings-pane');
|
|
this._settingsPane.show(panel.contentElement);
|
|
this._showSettingsPaneSetting = Common.settings.createSetting('networkShowSettingsToolbar', false);
|
|
this._showSettingsPaneSetting.addChangeListener(this._updateSettingsPaneVisibility.bind(this));
|
|
this._updateSettingsPaneVisibility();
|
|
|
|
this._filmStripPlaceholderElement = panel.contentElement.createChild('div', 'network-film-strip-placeholder');
|
|
|
|
// Create top overview component.
|
|
this._overviewPane = new PerfUI.TimelineOverviewPane('network');
|
|
this._overviewPane.addEventListener(
|
|
PerfUI.TimelineOverviewPane.Events.WindowChanged, this._onWindowChanged.bind(this));
|
|
this._overviewPane.element.id = 'network-overview-panel';
|
|
this._networkOverview = new Network.NetworkOverview();
|
|
this._overviewPane.setOverviewControls([this._networkOverview]);
|
|
this._overviewPlaceholderElement = panel.contentElement.createChild('div');
|
|
|
|
this._calculator = new Network.NetworkTransferTimeCalculator();
|
|
|
|
this._splitWidget = new UI.SplitWidget(true, false, 'networkPanelSplitViewState');
|
|
this._splitWidget.hideMain();
|
|
this._splitWidget.show(panel.contentElement);
|
|
|
|
panel.setDefaultFocusedChild(this._filterBar);
|
|
|
|
const initialSidebarWidth = 225;
|
|
const splitWidget = new UI.SplitWidget(true, false, 'networkPanelSidebarState', initialSidebarWidth);
|
|
splitWidget.hideSidebar();
|
|
splitWidget.enableShowModeSaving();
|
|
splitWidget.show(this.element);
|
|
this._sidebarLocation = UI.viewManager.createTabbedLocation(async () => {
|
|
UI.viewManager.showView('network');
|
|
splitWidget.showBoth();
|
|
}, 'network-sidebar', true);
|
|
const tabbedPane = this._sidebarLocation.tabbedPane();
|
|
tabbedPane.setMinimumSize(100, 25);
|
|
tabbedPane.element.classList.add('network-tabbed-pane');
|
|
tabbedPane.element.addEventListener('keydown', event => {
|
|
if (event.key !== 'Escape') {
|
|
return;
|
|
}
|
|
splitWidget.hideSidebar();
|
|
event.consume();
|
|
});
|
|
const closeSidebar = new UI.ToolbarButton(Common.UIString('Close'), 'largeicon-delete');
|
|
closeSidebar.addEventListener(UI.ToolbarButton.Events.Click, () => splitWidget.hideSidebar());
|
|
tabbedPane.rightToolbar().appendToolbarItem(closeSidebar);
|
|
splitWidget.setSidebarWidget(tabbedPane);
|
|
splitWidget.setMainWidget(panel);
|
|
splitWidget.setDefaultFocusedChild(panel);
|
|
this.setDefaultFocusedChild(splitWidget);
|
|
|
|
this._progressBarContainer = createElement('div');
|
|
|
|
/** @type {!Network.NetworkLogView} */
|
|
this._networkLogView =
|
|
new Network.NetworkLogView(this._filterBar, this._progressBarContainer, this._networkLogLargeRowsSetting);
|
|
this._splitWidget.setSidebarWidget(this._networkLogView);
|
|
|
|
this._fileSelectorElement =
|
|
UI.createFileSelectorElement(this._networkLogView.onLoadFromFile.bind(this._networkLogView));
|
|
panel.element.appendChild(this._fileSelectorElement);
|
|
|
|
this._detailsWidget = new UI.VBox();
|
|
this._detailsWidget.element.classList.add('network-details-view');
|
|
this._splitWidget.setMainWidget(this._detailsWidget);
|
|
|
|
this._closeButtonElement = createElement('div', 'dt-close-button');
|
|
this._closeButtonElement.addEventListener(
|
|
'click', async () => await UI.actionRegistry.action('network.hide-request-details').execute(), false);
|
|
this._closeButtonElement.style.margin = '0 5px';
|
|
|
|
this._networkLogShowOverviewSetting.addChangeListener(this._toggleShowOverview, this);
|
|
this._networkLogLargeRowsSetting.addChangeListener(this._toggleLargerRequests, this);
|
|
this._networkRecordFilmStripSetting.addChangeListener(this._toggleRecordFilmStrip, this);
|
|
|
|
this._preserveLogSetting = Common.moduleSetting('network_log.preserve-log');
|
|
|
|
this._throttlingSelect = this._createThrottlingConditionsSelect();
|
|
this._setupToolbarButtons(splitWidget);
|
|
|
|
this._toggleRecord(true);
|
|
this._toggleShowOverview();
|
|
this._toggleLargerRequests();
|
|
this._toggleRecordFilmStrip();
|
|
this._updateUI();
|
|
|
|
SDK.targetManager.addModelListener(
|
|
SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.WillReloadPage, this._willReloadPage, this);
|
|
SDK.targetManager.addModelListener(SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.Load, this._load, this);
|
|
this._networkLogView.addEventListener(Network.NetworkLogView.Events.RequestSelected, this._onRequestSelected, this);
|
|
this._networkLogView.addEventListener(
|
|
Network.NetworkLogView.Events.RequestActivated, this._onRequestActivated, this);
|
|
SDK.networkLog.addEventListener(SDK.NetworkLog.Events.RequestAdded, this._onUpdateRequest, this);
|
|
SDK.networkLog.addEventListener(SDK.NetworkLog.Events.RequestUpdated, this._onUpdateRequest, this);
|
|
SDK.networkLog.addEventListener(SDK.NetworkLog.Events.Reset, this._onNetworkLogReset, this);
|
|
}
|
|
|
|
/**
|
|
* @param {!Array<{filterType: !Network.NetworkLogView.FilterType, filterValue: string}>} filters
|
|
*/
|
|
static revealAndFilter(filters) {
|
|
const panel = Network.NetworkPanel._instance();
|
|
let filterString = '';
|
|
for (const filter of filters) {
|
|
filterString += `${filter.filterType}:${filter.filterValue} `;
|
|
}
|
|
panel._networkLogView.setTextFilterValue(filterString);
|
|
UI.viewManager.showView('network');
|
|
}
|
|
|
|
/**
|
|
* @return {!Network.NetworkPanel}
|
|
*/
|
|
static _instance() {
|
|
return /** @type {!Network.NetworkPanel} */ (self.runtime.sharedInstance(Network.NetworkPanel));
|
|
}
|
|
|
|
/**
|
|
* @return {!UI.ToolbarComboBox}
|
|
*/
|
|
throttlingSelectForTest() {
|
|
return this._throttlingSelect;
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_onWindowChanged(event) {
|
|
const startTime = Math.max(this._calculator.minimumBoundary(), event.data.startTime / 1000);
|
|
const endTime = Math.min(this._calculator.maximumBoundary(), event.data.endTime / 1000);
|
|
this._networkLogView.setWindow(startTime, endTime);
|
|
}
|
|
|
|
_setupToolbarButtons(splitWidget) {
|
|
const searchToggle = new UI.ToolbarToggle(ls`Search`, 'largeicon-search');
|
|
function updateSidebarToggle() {
|
|
const isSidebarShowing = splitWidget.showMode() !== UI.SplitWidget.ShowMode.OnlyMain;
|
|
searchToggle.setToggled(isSidebarShowing);
|
|
if (!isSidebarShowing) {
|
|
searchToggle.element.focus();
|
|
}
|
|
}
|
|
this._panelToolbar.appendToolbarItem(UI.Toolbar.createActionButton(this._toggleRecordAction));
|
|
const clearButton = new UI.ToolbarButton(Common.UIString('Clear'), 'largeicon-clear');
|
|
clearButton.addEventListener(UI.ToolbarButton.Events.Click, () => SDK.networkLog.reset(), this);
|
|
this._panelToolbar.appendToolbarItem(clearButton);
|
|
this._panelToolbar.appendSeparator();
|
|
|
|
this._panelToolbar.appendToolbarItem(this._filterBar.filterButton());
|
|
updateSidebarToggle();
|
|
splitWidget.addEventListener(UI.SplitWidget.Events.ShowModeChanged, updateSidebarToggle);
|
|
searchToggle.addEventListener(UI.ToolbarButton.Events.Click, () => {
|
|
if (splitWidget.showMode() === UI.SplitWidget.ShowMode.OnlyMain) {
|
|
splitWidget.showBoth();
|
|
} else {
|
|
splitWidget.hideSidebar();
|
|
}
|
|
});
|
|
this._panelToolbar.appendToolbarItem(searchToggle);
|
|
this._panelToolbar.appendSeparator();
|
|
|
|
this._panelToolbar.appendToolbarItem(new UI.ToolbarSettingCheckbox(
|
|
this._preserveLogSetting, Common.UIString('Do not clear log on page reload / navigation'),
|
|
Common.UIString('Preserve log')));
|
|
|
|
const disableCacheCheckbox = new UI.ToolbarSettingCheckbox(
|
|
Common.moduleSetting('cacheDisabled'), Common.UIString('Disable cache (while DevTools is open)'),
|
|
Common.UIString('Disable cache'));
|
|
this._panelToolbar.appendToolbarItem(disableCacheCheckbox);
|
|
|
|
this._panelToolbar.appendSeparator();
|
|
this._panelToolbar.appendToolbarItem(this._throttlingSelect);
|
|
|
|
this._rightToolbar.appendToolbarItem(new UI.ToolbarItem(this._progressBarContainer));
|
|
this._rightToolbar.appendSeparator();
|
|
this._rightToolbar.appendToolbarItem(
|
|
new UI.ToolbarSettingToggle(this._showSettingsPaneSetting, 'largeicon-settings-gear', ls`Network settings`));
|
|
|
|
const settingsToolbarLeft = new UI.Toolbar('', this._settingsPane.element);
|
|
settingsToolbarLeft.makeVertical();
|
|
settingsToolbarLeft.appendToolbarItem(
|
|
new UI.ToolbarSettingCheckbox(this._networkLogLargeRowsSetting, '', ls`Use large request rows`));
|
|
settingsToolbarLeft.appendToolbarItem(
|
|
new UI.ToolbarSettingCheckbox(this._networkLogShowOverviewSetting, '', ls`Show overview`));
|
|
|
|
const settingsToolbarRight = new UI.Toolbar('', this._settingsPane.element);
|
|
settingsToolbarRight.makeVertical();
|
|
settingsToolbarRight.appendToolbarItem(
|
|
new UI.ToolbarSettingCheckbox(Common.moduleSetting('network.group-by-frame'), '', ls`Group by frame`));
|
|
settingsToolbarRight.appendToolbarItem(
|
|
new UI.ToolbarSettingCheckbox(this._networkRecordFilmStripSetting, '', ls`Capture screenshots`));
|
|
|
|
this._panelToolbar.appendSeparator();
|
|
const importHarButton = new UI.ToolbarButton(ls`Import HAR file...`, 'largeicon-load');
|
|
importHarButton.addEventListener(UI.ToolbarButton.Events.Click, () => this._fileSelectorElement.click(), this);
|
|
this._panelToolbar.appendToolbarItem(importHarButton);
|
|
const exportHarButton = new UI.ToolbarButton(ls`Export HAR...`, 'largeicon-download');
|
|
exportHarButton.addEventListener(UI.ToolbarButton.Events.Click, () => this._networkLogView.exportAll(), this);
|
|
this._panelToolbar.appendToolbarItem(exportHarButton);
|
|
}
|
|
|
|
_updateSettingsPaneVisibility() {
|
|
this._settingsPane.element.classList.toggle('hidden', !this._showSettingsPaneSetting.get());
|
|
}
|
|
|
|
/**
|
|
* @return {!UI.ToolbarComboBox}
|
|
*/
|
|
_createThrottlingConditionsSelect() {
|
|
const toolbarItem = new UI.ToolbarComboBox(null, ls`Throttling`);
|
|
toolbarItem.setMaxWidth(160);
|
|
MobileThrottling.throttlingManager().decorateSelectWithNetworkThrottling(toolbarItem.selectElement());
|
|
return toolbarItem;
|
|
}
|
|
|
|
_toggleRecording() {
|
|
if (!this._preserveLogSetting.get() && !this._toggleRecordAction.toggled()) {
|
|
SDK.networkLog.reset();
|
|
}
|
|
this._toggleRecord(!this._toggleRecordAction.toggled());
|
|
}
|
|
|
|
/**
|
|
* @param {boolean} toggled
|
|
*/
|
|
_toggleRecord(toggled) {
|
|
this._toggleRecordAction.setToggled(toggled);
|
|
this._networkLogView.setRecording(toggled);
|
|
if (!toggled && this._filmStripRecorder) {
|
|
this._filmStripRecorder.stopRecording(this._filmStripAvailable.bind(this));
|
|
}
|
|
// TODO(einbinder) This should be moved to a setting/action that NetworkLog owns but NetworkPanel controls, but
|
|
// always be present in the command menu.
|
|
SDK.networkLog.setIsRecording(toggled);
|
|
}
|
|
|
|
/**
|
|
* @param {?SDK.FilmStripModel} filmStripModel
|
|
*/
|
|
_filmStripAvailable(filmStripModel) {
|
|
if (!filmStripModel) {
|
|
return;
|
|
}
|
|
const calculator = this._networkLogView.timeCalculator();
|
|
this._filmStripView.setModel(filmStripModel, calculator.minimumBoundary() * 1000, calculator.boundarySpan() * 1000);
|
|
this._networkOverview.setFilmStripModel(filmStripModel);
|
|
const timestamps = filmStripModel.frames().map(mapTimestamp);
|
|
|
|
/**
|
|
* @param {!SDK.FilmStripModel.Frame} frame
|
|
* @return {number}
|
|
*/
|
|
function mapTimestamp(frame) {
|
|
return frame.timestamp / 1000;
|
|
}
|
|
|
|
this._networkLogView.addFilmStripFrames(timestamps);
|
|
}
|
|
|
|
_onNetworkLogReset() {
|
|
Network.BlockedURLsPane.reset();
|
|
if (!this._preserveLogSetting.get()) {
|
|
this._calculator.reset();
|
|
this._overviewPane.reset();
|
|
}
|
|
if (this._filmStripView) {
|
|
this._resetFilmStripView();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_willReloadPage(event) {
|
|
this._toggleRecord(true);
|
|
if (this._pendingStopTimer) {
|
|
clearTimeout(this._pendingStopTimer);
|
|
delete this._pendingStopTimer;
|
|
}
|
|
if (this.isShowing() && this._filmStripRecorder) {
|
|
this._filmStripRecorder.startRecording();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_load(event) {
|
|
if (this._filmStripRecorder && this._filmStripRecorder.isRecording()) {
|
|
this._pendingStopTimer =
|
|
setTimeout(this._stopFilmStripRecording.bind(this), Network.NetworkPanel.displayScreenshotDelay);
|
|
}
|
|
}
|
|
|
|
_stopFilmStripRecording() {
|
|
this._filmStripRecorder.stopRecording(this._filmStripAvailable.bind(this));
|
|
delete this._pendingStopTimer;
|
|
}
|
|
|
|
_toggleLargerRequests() {
|
|
this._updateUI();
|
|
}
|
|
|
|
_toggleShowOverview() {
|
|
const toggled = this._networkLogShowOverviewSetting.get();
|
|
if (toggled) {
|
|
this._overviewPane.show(this._overviewPlaceholderElement);
|
|
} else {
|
|
this._overviewPane.detach();
|
|
}
|
|
this.doResize();
|
|
}
|
|
|
|
_toggleRecordFilmStrip() {
|
|
const toggled = this._networkRecordFilmStripSetting.get();
|
|
if (toggled && !this._filmStripRecorder) {
|
|
this._filmStripView = new PerfUI.FilmStripView();
|
|
this._filmStripView.setMode(PerfUI.FilmStripView.Modes.FrameBased);
|
|
this._filmStripView.element.classList.add('network-film-strip');
|
|
this._filmStripRecorder =
|
|
new Network.NetworkPanel.FilmStripRecorder(this._networkLogView.timeCalculator(), this._filmStripView);
|
|
this._filmStripView.show(this._filmStripPlaceholderElement);
|
|
this._filmStripView.addEventListener(PerfUI.FilmStripView.Events.FrameSelected, this._onFilmFrameSelected, this);
|
|
this._filmStripView.addEventListener(PerfUI.FilmStripView.Events.FrameEnter, this._onFilmFrameEnter, this);
|
|
this._filmStripView.addEventListener(PerfUI.FilmStripView.Events.FrameExit, this._onFilmFrameExit, this);
|
|
this._resetFilmStripView();
|
|
}
|
|
|
|
if (!toggled && this._filmStripRecorder) {
|
|
this._filmStripView.detach();
|
|
this._filmStripView = null;
|
|
this._filmStripRecorder = null;
|
|
}
|
|
}
|
|
|
|
_resetFilmStripView() {
|
|
const reloadShortcutDescriptor = UI.shortcutRegistry.shortcutDescriptorsForAction('inspector_main.reload')[0];
|
|
|
|
this._filmStripView.reset();
|
|
if (reloadShortcutDescriptor) {
|
|
this._filmStripView.setStatusText(
|
|
Common.UIString('Hit %s to reload and capture filmstrip.', reloadShortcutDescriptor.name));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {!Array.<!Element>}
|
|
*/
|
|
elementsToRestoreScrollPositionsFor() {
|
|
return this._networkLogView.elementsToRestoreScrollPositionsFor();
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
wasShown() {
|
|
UI.context.setFlavor(Network.NetworkPanel, this);
|
|
|
|
// Record the network tool load time after the panel has loaded.
|
|
Host.userMetrics.panelLoaded('network', 'DevTools.Launch.Network');
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
willHide() {
|
|
UI.context.setFlavor(Network.NetworkPanel, null);
|
|
}
|
|
|
|
/**
|
|
* @param {!SDK.NetworkRequest} request
|
|
*/
|
|
revealAndHighlightRequest(request) {
|
|
this._hideRequestPanel();
|
|
if (request) {
|
|
this._networkLogView.revealAndHighlightRequest(request);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!SDK.NetworkRequest} request
|
|
* @return {!Promise<?Network.NetworkItemView>}
|
|
*/
|
|
async selectRequest(request) {
|
|
await UI.viewManager.showView('network');
|
|
this._networkLogView.selectRequest(request);
|
|
return this._networkItemView;
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_onRowSizeChanged(event) {
|
|
this._updateUI();
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_onRequestSelected(event) {
|
|
const request = /** @type {?SDK.NetworkRequest} */ (event.data);
|
|
this._currentRequest = request;
|
|
this._networkOverview.setHighlightedRequest(request);
|
|
this._updateNetworkItemView();
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_onRequestActivated(event) {
|
|
const showPanel = /** @type {boolean} */ (event.data);
|
|
if (showPanel) {
|
|
this._showRequestPanel();
|
|
} else {
|
|
this._hideRequestPanel();
|
|
}
|
|
}
|
|
|
|
_showRequestPanel() {
|
|
this._clearNetworkItemView();
|
|
if (this._currentRequest) {
|
|
this._createNetworkItemView();
|
|
}
|
|
this._updateUI();
|
|
}
|
|
|
|
_hideRequestPanel() {
|
|
this._clearNetworkItemView();
|
|
this._splitWidget.hideMain();
|
|
this._updateUI();
|
|
}
|
|
|
|
_updateNetworkItemView() {
|
|
if (this._splitWidget.showMode() === UI.SplitWidget.ShowMode.Both) {
|
|
this._clearNetworkItemView();
|
|
this._createNetworkItemView();
|
|
this._updateUI();
|
|
}
|
|
}
|
|
|
|
_clearNetworkItemView() {
|
|
if (this._networkItemView) {
|
|
this._networkItemView.detach();
|
|
this._networkItemView = null;
|
|
}
|
|
}
|
|
|
|
_createNetworkItemView() {
|
|
if (!this._currentRequest) {
|
|
return;
|
|
}
|
|
this._networkItemView = new Network.NetworkItemView(this._currentRequest, this._networkLogView.timeCalculator());
|
|
this._networkItemView.leftToolbar().appendToolbarItem(new UI.ToolbarItem(this._closeButtonElement));
|
|
this._networkItemView.show(this._detailsWidget.element);
|
|
this._splitWidget.showBoth();
|
|
}
|
|
|
|
_updateUI() {
|
|
this._detailsWidget.element.classList.toggle(
|
|
'network-details-view-tall-header', this._networkLogLargeRowsSetting.get());
|
|
this._networkLogView.switchViewMode(!this._splitWidget.isResizable());
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @param {!Event} event
|
|
* @param {!UI.ContextMenu} contextMenu
|
|
* @param {!Object} target
|
|
* @this {Network.NetworkPanel}
|
|
*/
|
|
appendApplicableItems(event, contextMenu, target) {
|
|
/**
|
|
* @this {Network.NetworkPanel}
|
|
*/
|
|
function reveal(request) {
|
|
UI.viewManager.showView('network').then(this.revealAndHighlightRequest.bind(this, request));
|
|
}
|
|
|
|
/**
|
|
* @this {Network.NetworkPanel}
|
|
*/
|
|
function appendRevealItem(request) {
|
|
contextMenu.revealSection().appendItem(Common.UIString('Reveal in Network panel'), reveal.bind(this, request));
|
|
}
|
|
|
|
if (event.target.isSelfOrDescendant(this.element)) {
|
|
return;
|
|
}
|
|
|
|
if (target instanceof SDK.Resource) {
|
|
const resource = /** @type {!SDK.Resource} */ (target);
|
|
if (resource.request) {
|
|
appendRevealItem.call(this, resource.request);
|
|
}
|
|
return;
|
|
}
|
|
if (target instanceof Workspace.UISourceCode) {
|
|
const uiSourceCode = /** @type {!Workspace.UISourceCode} */ (target);
|
|
const resource = Bindings.resourceForURL(uiSourceCode.url());
|
|
if (resource && resource.request) {
|
|
appendRevealItem.call(this, resource.request);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!(target instanceof SDK.NetworkRequest)) {
|
|
return;
|
|
}
|
|
const request = /** @type {!SDK.NetworkRequest} */ (target);
|
|
if (this._networkItemView && this._networkItemView.isShowing() && this._networkItemView.request() === request) {
|
|
return;
|
|
}
|
|
|
|
appendRevealItem.call(this, request);
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_onFilmFrameSelected(event) {
|
|
const timestamp = /** @type {number} */ (event.data);
|
|
this._overviewPane.setWindowTimes(0, timestamp);
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_onFilmFrameEnter(event) {
|
|
const timestamp = /** @type {number} */ (event.data);
|
|
this._networkOverview.selectFilmStripFrame(timestamp);
|
|
this._networkLogView.selectFilmStripFrame(timestamp / 1000);
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_onFilmFrameExit(event) {
|
|
this._networkOverview.clearFilmStripFrame();
|
|
this._networkLogView.clearFilmStripFrame();
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_onUpdateRequest(event) {
|
|
const request = /** @type {!SDK.NetworkRequest} */ (event.data);
|
|
this._calculator.updateBoundaries(request);
|
|
// FIXME: Unify all time units across the frontend!
|
|
this._overviewPane.setBounds(this._calculator.minimumBoundary() * 1000, this._calculator.maximumBoundary() * 1000);
|
|
this._networkOverview.updateRequest(request);
|
|
this._overviewPane.scheduleUpdate();
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @param {string} locationName
|
|
* @return {?UI.ViewLocation}
|
|
*/
|
|
resolveLocation(locationName) {
|
|
if (locationName === 'network-sidebar') {
|
|
return this._sidebarLocation;
|
|
}
|
|
return null;
|
|
}
|
|
};
|
|
|
|
Network.NetworkPanel.displayScreenshotDelay = 1000;
|
|
|
|
/**
|
|
* @implements {UI.ContextMenu.Provider}
|
|
* @unrestricted
|
|
*/
|
|
Network.NetworkPanel.ContextMenuProvider = class {
|
|
/**
|
|
* @override
|
|
* @param {!Event} event
|
|
* @param {!UI.ContextMenu} contextMenu
|
|
* @param {!Object} target
|
|
*/
|
|
appendApplicableItems(event, contextMenu, target) {
|
|
Network.NetworkPanel._instance().appendApplicableItems(event, contextMenu, target);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @implements {Common.Revealer}
|
|
* @unrestricted
|
|
*/
|
|
Network.NetworkPanel.RequestRevealer = class {
|
|
/**
|
|
* @override
|
|
* @param {!Object} request
|
|
* @return {!Promise}
|
|
*/
|
|
reveal(request) {
|
|
if (!(request instanceof SDK.NetworkRequest)) {
|
|
return Promise.reject(new Error('Internal error: not a network request'));
|
|
}
|
|
const panel = Network.NetworkPanel._instance();
|
|
return UI.viewManager.showView('network').then(panel.revealAndHighlightRequest.bind(panel, request));
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* @implements {SDK.TracingManagerClient}
|
|
*/
|
|
Network.NetworkPanel.FilmStripRecorder = class {
|
|
/**
|
|
* @param {!Network.NetworkTimeCalculator} timeCalculator
|
|
* @param {!PerfUI.FilmStripView} filmStripView
|
|
*/
|
|
constructor(timeCalculator, filmStripView) {
|
|
/** @type {?SDK.TracingManager} */
|
|
this._tracingManager = null;
|
|
/** @type {?SDK.ResourceTreeModel} */
|
|
this._resourceTreeModel = null;
|
|
this._timeCalculator = timeCalculator;
|
|
this._filmStripView = filmStripView;
|
|
/** @type {?SDK.TracingModel} */
|
|
this._tracingModel = null;
|
|
/** @type {?function(?SDK.FilmStripModel)} */
|
|
this._callback = null;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @param {!Array.<!SDK.TracingManager.EventPayload>} events
|
|
*/
|
|
traceEventsCollected(events) {
|
|
if (this._tracingModel) {
|
|
this._tracingModel.addEvents(events);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
tracingComplete() {
|
|
if (!this._tracingModel || !this._tracingManager) {
|
|
return;
|
|
}
|
|
this._tracingModel.tracingComplete();
|
|
this._tracingManager = null;
|
|
this._callback(new SDK.FilmStripModel(this._tracingModel, this._timeCalculator.minimumBoundary() * 1000));
|
|
this._callback = null;
|
|
if (this._resourceTreeModel) {
|
|
this._resourceTreeModel.resumeReload();
|
|
}
|
|
this._resourceTreeModel = null;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
tracingBufferUsage() {
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @param {number} progress
|
|
*/
|
|
eventsRetrievalProgress(progress) {
|
|
}
|
|
|
|
startRecording() {
|
|
this._filmStripView.reset();
|
|
this._filmStripView.setStatusText(Common.UIString('Recording frames...'));
|
|
const tracingManagers = SDK.targetManager.models(SDK.TracingManager);
|
|
if (this._tracingManager || !tracingManagers.length) {
|
|
return;
|
|
}
|
|
|
|
this._tracingManager = tracingManagers[0];
|
|
this._resourceTreeModel = this._tracingManager.target().model(SDK.ResourceTreeModel);
|
|
if (this._tracingModel) {
|
|
this._tracingModel.dispose();
|
|
}
|
|
this._tracingModel = new SDK.TracingModel(new Bindings.TempFileBackingStorage());
|
|
this._tracingManager.start(this, '-*,disabled-by-default-devtools.screenshot', '');
|
|
|
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.FilmStripStartedRecording);
|
|
}
|
|
|
|
/**
|
|
* @return {boolean}
|
|
*/
|
|
isRecording() {
|
|
return !!this._tracingManager;
|
|
}
|
|
|
|
/**
|
|
* @param {function(?SDK.FilmStripModel)} callback
|
|
*/
|
|
stopRecording(callback) {
|
|
if (!this._tracingManager) {
|
|
return;
|
|
}
|
|
|
|
this._tracingManager.stop();
|
|
if (this._resourceTreeModel) {
|
|
this._resourceTreeModel.suspendReload();
|
|
}
|
|
this._callback = callback;
|
|
this._filmStripView.setStatusText(Common.UIString('Fetching frames...'));
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @implements {UI.ActionDelegate}
|
|
*/
|
|
Network.NetworkPanel.ActionDelegate = class {
|
|
/**
|
|
* @override
|
|
* @param {!UI.Context} context
|
|
* @param {string} actionId
|
|
* @return {boolean}
|
|
*/
|
|
handleAction(context, actionId) {
|
|
const panel = UI.context.flavor(Network.NetworkPanel);
|
|
console.assert(panel && panel instanceof Network.NetworkPanel);
|
|
switch (actionId) {
|
|
case 'network.toggle-recording':
|
|
panel._toggleRecording();
|
|
return true;
|
|
case 'network.hide-request-details':
|
|
if (!panel._networkItemView) {
|
|
return false;
|
|
}
|
|
panel._hideRequestPanel();
|
|
panel._networkLogView.resetFocus();
|
|
return true;
|
|
case 'network.search':
|
|
const selection = UI.inspectorView.element.window().getSelection();
|
|
let queryCandidate = '';
|
|
if (selection.rangeCount) {
|
|
queryCandidate = selection.toString().replace(/\r?\n.*/, '');
|
|
}
|
|
Network.SearchNetworkView.openSearch(queryCandidate);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @implements {Common.Revealer}
|
|
*/
|
|
Network.NetworkPanel.RequestLocationRevealer = class {
|
|
/**
|
|
* @override
|
|
* @param {!Object} match
|
|
* @return {!Promise}
|
|
*/
|
|
async reveal(match) {
|
|
const location = /** @type {!Network.UIRequestLocation} */ (match);
|
|
const view = await Network.NetworkPanel._instance().selectRequest(location.request);
|
|
if (!view) {
|
|
return;
|
|
}
|
|
if (location.searchMatch) {
|
|
await view.revealResponseBody(location.searchMatch.lineNumber);
|
|
}
|
|
if (location.requestHeader) {
|
|
view.revealRequestHeader(location.requestHeader.name);
|
|
}
|
|
if (location.responseHeader) {
|
|
view.revealResponseHeader(location.responseHeader.name);
|
|
}
|
|
}
|
|
};
|
|
|
|
Network.SearchNetworkView = class extends Search.SearchView {
|
|
constructor() {
|
|
super('network');
|
|
}
|
|
|
|
/**
|
|
* @param {string} query
|
|
* @param {boolean=} searchImmediately
|
|
* @return {!Promise<!Search.SearchView>}
|
|
*/
|
|
static async openSearch(query, searchImmediately) {
|
|
await UI.viewManager.showView('network.search-network-tab');
|
|
const searchView =
|
|
/** @type {!Network.SearchNetworkView} */ (self.runtime.sharedInstance(Network.SearchNetworkView));
|
|
searchView.toggle(query, !!searchImmediately);
|
|
return searchView;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {!Search.SearchScope}
|
|
*/
|
|
createScope() {
|
|
return new Network.NetworkSearchScope();
|
|
}
|
|
};
|