зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1358414 - Introduce column resizer in request list; r=Honza
Adding feature to netmonitor for resizing of columns. In this patch the functionality is hidden behind the pref devtools.netmonitor.features.resizeColumns. This feature is currently turned off - false. Differential Revision: https://phabricator.services.mozilla.com/D22719 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
b9a96f34ff
Коммит
f098dc0c1e
|
@ -15,6 +15,7 @@ const {
|
|||
SELECT_DETAILS_PANEL_TAB,
|
||||
TOGGLE_COLUMN,
|
||||
WATERFALL_RESIZE,
|
||||
SET_COLUMNS_WIDTH,
|
||||
} = require("../constants");
|
||||
|
||||
const { getDisplayedRequests } = require("../selectors/index");
|
||||
|
@ -137,6 +138,18 @@ function toggleColumn(column) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set width of multiple columns
|
||||
*
|
||||
* @param {array} widths - array of pairs {name, width}
|
||||
*/
|
||||
function setColumnsWidth(widths) {
|
||||
return {
|
||||
type: SET_COLUMNS_WIDTH,
|
||||
widths,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle network details panel.
|
||||
*/
|
||||
|
@ -179,6 +192,7 @@ module.exports = {
|
|||
resizeWaterfall,
|
||||
selectDetailsPanelTab,
|
||||
toggleColumn,
|
||||
setColumnsWidth,
|
||||
toggleNetworkDetails,
|
||||
togglePersistentLogs,
|
||||
toggleBrowserCache,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
.request-list-empty-notice {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.empty-notice-element {
|
||||
|
@ -59,16 +59,18 @@
|
|||
.requests-list-table {
|
||||
/* Reset default browser style of <table> */
|
||||
border-spacing: 0;
|
||||
width: 100%;
|
||||
/* The layout must be fixed for resizing of columns to work.
|
||||
The layout is based on the first row.
|
||||
Set the width of those cells, and the rest of the table follows. */
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.requests-list-column {
|
||||
cursor: default;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
max-width: 50px;
|
||||
min-width: 50px;
|
||||
|
||||
/* Reset default browser style of <td> */
|
||||
padding: 0;
|
||||
|
@ -108,11 +110,11 @@
|
|||
transparent 85%) 1 1;
|
||||
border-width: 0;
|
||||
border-inline-start-width: 1px;
|
||||
padding-inline-start: 16px;
|
||||
width: 100%;
|
||||
min-height: 23px;
|
||||
text-align: center;
|
||||
color: inherit;
|
||||
padding: 1px 4px;
|
||||
}
|
||||
|
||||
.requests-list-header-button::-moz-focus-inner {
|
||||
|
@ -129,7 +131,7 @@
|
|||
text-align: center;
|
||||
vertical-align: middle;
|
||||
/* Align button text to center */
|
||||
width: calc(100% - 8px);
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
@ -162,13 +164,32 @@
|
|||
border-image: linear-gradient(var(--theme-splitter-color), var(--theme-splitter-color)) 1 1;
|
||||
}
|
||||
|
||||
/* Requests list headers column-resizer */
|
||||
|
||||
.requests-list-headers .column-resizer {
|
||||
z-index: 1000;
|
||||
cursor: ew-resize;
|
||||
margin-left: -3px;
|
||||
width: 7px;
|
||||
min-height: 23px;
|
||||
position: absolute;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure headers are not processing any mouse
|
||||
* events. This is good for performance during dragging.
|
||||
*/
|
||||
.requests-list-headers.dragging {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Requests list column */
|
||||
|
||||
/* Status column */
|
||||
|
||||
.requests-list-status {
|
||||
min-width: 70px;
|
||||
/* Don't ellipsize status codes */
|
||||
/* Don't ellipsize status codes */
|
||||
text-overflow: initial;
|
||||
}
|
||||
|
||||
|
@ -226,18 +247,6 @@
|
|||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
/* Method column */
|
||||
|
||||
.requests-list-method {
|
||||
min-width: 85px;
|
||||
}
|
||||
|
||||
/* File column */
|
||||
|
||||
.requests-list-file {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.requests-list-file.requests-list-column {
|
||||
text-align: start;
|
||||
}
|
||||
|
@ -246,73 +255,6 @@
|
|||
filter: brightness(1.3);
|
||||
}
|
||||
|
||||
/* Protocol column */
|
||||
|
||||
.requests-list-protocol {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
/* Cookies column */
|
||||
|
||||
.requests-list-cookies {
|
||||
width: 6%;
|
||||
}
|
||||
|
||||
/* Set Cookies column */
|
||||
|
||||
.requests-list-set-cookies {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
/* Scheme column */
|
||||
|
||||
.requests-list-scheme {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
/* Start Time column */
|
||||
|
||||
.requests-list-start-time {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
/* End Time column */
|
||||
|
||||
.requests-list-end-time {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
/* Response Time column */
|
||||
|
||||
.requests-list-response-time {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
/* Duration column */
|
||||
|
||||
.requests-list-duration-time {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
/* Latency column */
|
||||
|
||||
.requests-list-latency-time {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
/* Response header columns */
|
||||
|
||||
.requests-list-response-header {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
/* Domain column */
|
||||
|
||||
.requests-list-domain {
|
||||
min-width: 100px;
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.requests-list-domain.requests-list-column {
|
||||
text-align: start;
|
||||
}
|
||||
|
@ -367,18 +309,6 @@
|
|||
filter: brightness(500%);
|
||||
}
|
||||
|
||||
/* RemoteIP column */
|
||||
|
||||
.requests-list-remoteip {
|
||||
width: 9%;
|
||||
}
|
||||
|
||||
/* Cause column */
|
||||
|
||||
.requests-list-cause {
|
||||
min-width: 75px;
|
||||
}
|
||||
|
||||
.request-list-item .requests-list-cause.requests-list-column {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
@ -396,30 +326,9 @@
|
|||
margin-inline-end: 3px;
|
||||
}
|
||||
|
||||
/* Type column */
|
||||
|
||||
.requests-list-type {
|
||||
min-width: 65px;
|
||||
}
|
||||
|
||||
/* Transferred column */
|
||||
|
||||
.requests-list-transferred {
|
||||
min-width: 110px;
|
||||
}
|
||||
|
||||
/* Size column */
|
||||
|
||||
.requests-list-size {
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
/* Waterfall column */
|
||||
|
||||
.requests-list-waterfall {
|
||||
width: 25vw;
|
||||
max-width: 25vw;
|
||||
min-width: 25vw;
|
||||
background-repeat: repeat-y;
|
||||
background-position: left center;
|
||||
/* Background created on a <canvas> in js. */
|
||||
|
@ -572,10 +481,6 @@
|
|||
/* Responsive web design support */
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.requests-list-header-button {
|
||||
padding-inline-start: 8px;
|
||||
}
|
||||
|
||||
.requests-list-status-code {
|
||||
width: auto;
|
||||
}
|
||||
|
|
|
@ -123,6 +123,10 @@ class RequestListContent extends Component {
|
|||
window.removeEventListener("resize", this.onResize);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removing onResize() method causes perf regression - too many repaints of the panel.
|
||||
* So it is needed in ComponentDidMount and ComponentDidUpdate. See Bug 1532914.
|
||||
*/
|
||||
onResize() {
|
||||
const parent = this.refs.scrollEl.parentNode;
|
||||
this.refs.scrollEl.style.width = parent.offsetWidth + "px";
|
||||
|
|
|
@ -15,7 +15,6 @@ const { getPerformanceAnalysisURL } = require("../utils/mdn-utils");
|
|||
|
||||
// Components
|
||||
const MDNLink = createFactory(require("devtools/client/shared/components/MdnLink"));
|
||||
const RequestListHeader = createFactory(require("./RequestListHeader"));
|
||||
|
||||
const { button, div, span } = dom;
|
||||
|
||||
|
@ -45,7 +44,6 @@ class RequestListEmptyNotice extends Component {
|
|||
{
|
||||
className: "request-list-empty-notice",
|
||||
},
|
||||
RequestListHeader(),
|
||||
div({ className: "notice-reload-message empty-notice-element" },
|
||||
span(null, RELOAD_NOTICE_1),
|
||||
button(
|
||||
|
|
|
@ -4,22 +4,36 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { Component } = require("devtools/client/shared/vendor/react");
|
||||
const Services = require("Services");
|
||||
const { createRef, Component, createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { connect } = require("devtools/client/shared/redux/visibility-handler-connect");
|
||||
const { getTheme, addThemeObserver, removeThemeObserver } =
|
||||
require("devtools/client/shared/theme");
|
||||
const {
|
||||
getTheme,
|
||||
addThemeObserver,
|
||||
removeThemeObserver,
|
||||
} = require("devtools/client/shared/theme");
|
||||
const Actions = require("../actions/index");
|
||||
const { HEADERS, REQUESTS_WATERFALL } = require("../constants");
|
||||
const {
|
||||
HEADERS,
|
||||
REQUESTS_WATERFALL,
|
||||
MIN_COLUMN_WIDTH,
|
||||
DEFAULT_COLUMN_WIDTH,
|
||||
} = require("../constants");
|
||||
const { getWaterfallScale } = require("../selectors/index");
|
||||
const { getFormattedTime } = require("../utils/format-utils");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const RequestListHeaderContextMenu = require("../widgets/RequestListHeaderContextMenu");
|
||||
const WaterfallBackground = require("../widgets/WaterfallBackground");
|
||||
const Draggable = createFactory(require("devtools/client/shared/components/splitter/Draggable"));
|
||||
|
||||
const { div, button } = dom;
|
||||
|
||||
// Support for columns resizing is currently hidden behind this pref.
|
||||
const RESIZE_COLUMNS =
|
||||
Services.prefs.getBoolPref("devtools.netmonitor.features.resizeColumns");
|
||||
|
||||
/**
|
||||
* Render the request list header with sorting arrows for columns.
|
||||
* Displays tick marks in the waterfall column header.
|
||||
|
@ -36,11 +50,15 @@ class RequestListHeader extends Component {
|
|||
sortBy: PropTypes.func.isRequired,
|
||||
toggleColumn: PropTypes.func.isRequired,
|
||||
waterfallWidth: PropTypes.number,
|
||||
columnsData: PropTypes.object.isRequired,
|
||||
setColumnsWidth: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.requestListHeader = createRef();
|
||||
|
||||
this.onContextMenu = this.onContextMenu.bind(this);
|
||||
this.drawBackground = this.drawBackground.bind(this);
|
||||
this.resizeWaterfall = this.resizeWaterfall.bind(this);
|
||||
|
@ -60,6 +78,10 @@ class RequestListHeader extends Component {
|
|||
// Create the object that takes care of drawing the waterfall canvas background
|
||||
this.background = new WaterfallBackground(document);
|
||||
this.drawBackground();
|
||||
// When visible columns add up to less or more than 100% => update widths in prefs.
|
||||
if (this.shouldUpdateWidths()) {
|
||||
this.updateColumnsWidth();
|
||||
}
|
||||
this.resizeWaterfall();
|
||||
window.addEventListener("resize", this.resizeWaterfall);
|
||||
addThemeObserver(this.drawBackground);
|
||||
|
@ -67,6 +89,12 @@ class RequestListHeader extends Component {
|
|||
|
||||
componentDidUpdate() {
|
||||
this.drawBackground();
|
||||
// check if the widths in prefs need to be updated
|
||||
// e.g. after hide/show column
|
||||
if (this.shouldUpdateWidths()) {
|
||||
this.updateColumnsWidth();
|
||||
this.resizeWaterfall();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -163,54 +191,376 @@ class RequestListHeader extends Component {
|
|||
return div({ className }, label);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { columns, scale, sort, sortBy, waterfallWidth } = this.props;
|
||||
// Dragging Events
|
||||
|
||||
/**
|
||||
* Set 'resizing' cursor on entire container dragging.
|
||||
* This avoids cursor-flickering when the mouse leaves
|
||||
* the column-resizer area (happens frequently).
|
||||
*/
|
||||
onStartMove() {
|
||||
// Set cursor to dragging
|
||||
const container = document.querySelector(".request-list-container");
|
||||
container.style.cursor = "ew-resize";
|
||||
// Class .dragging is used to disable pointer events while dragging - see css.
|
||||
this.requestListHeader.classList.add("dragging");
|
||||
}
|
||||
|
||||
/**
|
||||
* A handler that calculates the new width of the columns
|
||||
* based on mouse position and adjusts the width.
|
||||
*/
|
||||
onMove(name, x) {
|
||||
const parentEl = document.querySelector(".requests-list-headers");
|
||||
const parentWidth = parentEl.getBoundingClientRect().width;
|
||||
|
||||
// Get the current column handle and save its old width
|
||||
// before changing so we can compute the adjustment in width
|
||||
const headerRef = this.refs[`${name}Header`];
|
||||
const headerRefRect = headerRef.getBoundingClientRect();
|
||||
const oldWidth = headerRefRect.width;
|
||||
|
||||
// Get the column handle that will compensate the width change.
|
||||
const compensateHeaderName = this.getCompensateHeader();
|
||||
|
||||
if (name === compensateHeaderName) {
|
||||
// this is the case where we are resizing waterfall
|
||||
this.moveWaterfall(x, parentWidth);
|
||||
return;
|
||||
}
|
||||
|
||||
const compensateHeaderRef = this.refs[`${compensateHeaderName}Header`];
|
||||
const compensateHeaderRefRect = compensateHeaderRef.getBoundingClientRect();
|
||||
const oldCompensateWidth = compensateHeaderRefRect.width;
|
||||
const sumOfBothColumns = oldWidth + oldCompensateWidth;
|
||||
|
||||
// Get minimal widths for both changed columns (in px).
|
||||
const minWidth = this.getMinWidth(name);
|
||||
const minCompensateWidth = this.getMinWidth(compensateHeaderName);
|
||||
|
||||
// Calculate new width (according to the mouse x-position) and set to style.
|
||||
// Do not allow to set it below minWidth.
|
||||
const newWidth = Math.max(x - headerRefRect.left, minWidth);
|
||||
headerRef.style.width = `${this.px2percent(newWidth, parentWidth)}%`;
|
||||
const adjustment = oldWidth - newWidth;
|
||||
|
||||
// Calculate new compensate width as the original width + adjustment.
|
||||
// Do not allow to set it below minCompensateWidth.
|
||||
const newCompensateWidth =
|
||||
Math.max(adjustment + oldCompensateWidth, minCompensateWidth);
|
||||
compensateHeaderRef.style.width =
|
||||
`${this.px2percent(newCompensateWidth, parentWidth)}%`;
|
||||
|
||||
// Do not allow to reset size of column when compensate column is at minWidth.
|
||||
if (newCompensateWidth === minCompensateWidth) {
|
||||
headerRef.style.width =
|
||||
`${this.px2percent((sumOfBothColumns - newCompensateWidth), parentWidth)}%`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* After resizing - we get the width for each 'column'
|
||||
* and convert it into % and store it in user prefs.
|
||||
* Also resets the 'resizing' cursor back to initial.
|
||||
*/
|
||||
onStopMove() {
|
||||
this.updateColumnsWidth();
|
||||
// If waterfall is visible and width has changed, call resizeWaterfall.
|
||||
const waterfallRef = this.refs.waterfallHeader;
|
||||
if (waterfallRef) {
|
||||
const { waterfallWidth } = this.props;
|
||||
const realWaterfallWidth = waterfallRef.getBoundingClientRect().width;
|
||||
if (Math.round(waterfallWidth) !== Math.round(realWaterfallWidth)) {
|
||||
this.resizeWaterfall();
|
||||
}
|
||||
}
|
||||
|
||||
// Restore cursor back to default.
|
||||
const container = document.querySelector(".request-list-container");
|
||||
container.style.cursor = "initial";
|
||||
this.requestListHeader.classList.remove("dragging");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the name of the column that will compensate
|
||||
* the width change. It should be the last column before waterfall,
|
||||
* (if waterfall visible) otherwise it is simply the last visible column.
|
||||
*/
|
||||
getCompensateHeader() {
|
||||
const visibleColumns = this.getVisibleColumns();
|
||||
const lastColumn = visibleColumns[visibleColumns.length - 1].name;
|
||||
const delta = (lastColumn === "waterfall") ? 2 : 1;
|
||||
return visibleColumns[visibleColumns.length - delta].name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from onMove() when resizing waterfall column
|
||||
* because waterfall is a special case, where ALL other
|
||||
* columns are made smaller when waterfall is bigger and vice versa.
|
||||
*/
|
||||
moveWaterfall(x, parentWidth) {
|
||||
const visibleColumns = this.getVisibleColumns();
|
||||
const minWaterfall = this.getMinWidth("waterfall");
|
||||
const waterfallRef = this.refs.waterfallHeader;
|
||||
|
||||
// Compute and set style.width for waterfall.
|
||||
const waterfallRefRect = waterfallRef.getBoundingClientRect();
|
||||
const oldWidth = waterfallRefRect.width;
|
||||
const adjustment = waterfallRefRect.left - x;
|
||||
if (this.allColumnsAtMinWidth() && adjustment > 0) {
|
||||
// When we want to make waterfall wider but all
|
||||
// other columns are already at minWidth => return.
|
||||
return;
|
||||
}
|
||||
|
||||
const newWidth = Math.max(oldWidth + adjustment, minWaterfall);
|
||||
|
||||
// Now distribute evenly the change in width to all other columns except waterfall.
|
||||
const changeInWidth = oldWidth - newWidth;
|
||||
const widths = this.autoSizeWidths(changeInWidth, visibleColumns);
|
||||
|
||||
// Set the new computed width for waterfall into array widths.
|
||||
widths[widths.length - 1] = newWidth;
|
||||
|
||||
// Update style for all columns from array widths.
|
||||
let i = 0;
|
||||
visibleColumns.forEach(col => {
|
||||
const name = col.name;
|
||||
const headerRef = this.refs[`${name}Header`];
|
||||
headerRef.style.width = `${this.px2percent(widths[i], parentWidth)}%`;
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that checks if all columns have reached their minWidth.
|
||||
* This can happen when making waterfall column wider.
|
||||
*/
|
||||
allColumnsAtMinWidth() {
|
||||
const visibleColumns = this.getVisibleColumns();
|
||||
// Do not check width for waterfall because
|
||||
// when all are getting smaller, waterfall is getting bigger.
|
||||
for (let i = 0; i < visibleColumns.length - 1; i++) {
|
||||
const name = visibleColumns[i].name;
|
||||
const headerRef = this.refs[`${name}Header`];
|
||||
const minColWidth = this.getMinWidth(name);
|
||||
if (headerRef.getBoundingClientRect().width > minColWidth) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method takes the total change in width for waterfall column
|
||||
* and distributes it among all other columns. Returns an array
|
||||
* where all visible columns have newly computed width in pixels.
|
||||
*/
|
||||
autoSizeWidths(changeInWidth, visibleColumns) {
|
||||
const widths = visibleColumns.map(col => {
|
||||
const headerRef = this.refs[`${col.name}Header`];
|
||||
const colWidth = headerRef.getBoundingClientRect().width;
|
||||
return colWidth;
|
||||
});
|
||||
|
||||
// Divide changeInWidth among all columns but waterfall (that's why -1).
|
||||
const changeInWidthPerColumn = changeInWidth / (widths.length - 1);
|
||||
|
||||
while (changeInWidth) {
|
||||
const lastChangeInWidth = changeInWidth;
|
||||
// In the loop adjust all columns except last one - waterfall
|
||||
for (let i = 0; i < widths.length - 1; i++) {
|
||||
const name = visibleColumns[i].name;
|
||||
const minColWidth = this.getMinWidth(name);
|
||||
const newColWidth = Math.max(widths[i] + changeInWidthPerColumn, minColWidth);
|
||||
|
||||
widths[i] = newColWidth;
|
||||
if (changeInWidth > 0) {
|
||||
changeInWidth -= (newColWidth - widths[i]);
|
||||
} else {
|
||||
changeInWidth += (newColWidth - widths[i]);
|
||||
}
|
||||
if (!changeInWidth) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastChangeInWidth == changeInWidth) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return widths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method returns 'true' - if the column widths need to be updated
|
||||
* when the total % is less or more than 100%.
|
||||
* It returns 'false' if they add up to 100% => no need to update.
|
||||
*/
|
||||
shouldUpdateWidths() {
|
||||
const visibleColumns = this.getVisibleColumns();
|
||||
let totalPercent = 0;
|
||||
|
||||
visibleColumns.forEach(col => {
|
||||
const name = col.name;
|
||||
const headerRef = this.refs[`${name}Header`];
|
||||
// Get column width from style.
|
||||
let widthFromStyle = 0;
|
||||
// In case the column is in visibleColumns but has display:none
|
||||
// we don't want to count its style.width into totalPercent.
|
||||
if (headerRef.getBoundingClientRect().width > 0) {
|
||||
widthFromStyle = headerRef.style.width.slice(0, -1);
|
||||
}
|
||||
totalPercent += +widthFromStyle; // + converts it to a number
|
||||
});
|
||||
|
||||
// Do not update if total percent is from 99-101% or when it is 0
|
||||
// - it means that no columns are displayed (e.g. other panel is currently selected).
|
||||
return Math.round(totalPercent) !== 100 && totalPercent !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method reads real width of each column header
|
||||
* and updates the style.width for that header.
|
||||
* It returns updated columnsData.
|
||||
*/
|
||||
updateColumnsWidth() {
|
||||
const visibleColumns = this.getVisibleColumns();
|
||||
const parentEl = document.querySelector(".requests-list-headers");
|
||||
const parentElRect = parentEl.getBoundingClientRect();
|
||||
const parentWidth = parentElRect.width;
|
||||
const newWidths = [];
|
||||
visibleColumns.forEach(col => {
|
||||
const name = col.name;
|
||||
const headerRef = this.refs[`${name}Header`];
|
||||
const headerWidth = headerRef.getBoundingClientRect().width;
|
||||
|
||||
// Get actual column width, change into %, update style
|
||||
const width = this.px2percent(headerWidth, parentWidth);
|
||||
|
||||
if (width > 0) {
|
||||
// This prevents saving width 0 for waterfall when it is not showing for
|
||||
// @media (max-width: 700px)
|
||||
newWidths.push({name, width});
|
||||
}
|
||||
});
|
||||
this.props.setColumnsWidth(newWidths);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to convert pixels into percent based on parent container width
|
||||
*/
|
||||
px2percent(pxWidth, parentWidth) {
|
||||
const percent = Math.round((100 * pxWidth / parentWidth) * 100) / 100;
|
||||
return percent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get visibleColumns;
|
||||
*/
|
||||
getVisibleColumns() {
|
||||
const { columns } = this.props;
|
||||
return HEADERS.filter((header) => columns[header.name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get minWidth from columnsData;
|
||||
*/
|
||||
getMinWidth(colName) {
|
||||
const columnsData = this.props.columnsData;
|
||||
if (columnsData.has(colName)) {
|
||||
return columnsData.get(colName).minWidth;
|
||||
}
|
||||
return MIN_COLUMN_WIDTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render one column header from the table headers.
|
||||
*/
|
||||
renderColumn(header) {
|
||||
const columnsData = this.props.columnsData;
|
||||
const visibleColumns = this.getVisibleColumns();
|
||||
const lastVisibleColumn = visibleColumns[visibleColumns.length - 1].name;
|
||||
const name = header.name;
|
||||
const boxName = header.boxName || name;
|
||||
const label = header.noLocalization
|
||||
? name : L10N.getStr(`netmonitor.toolbar.${header.label || name}`);
|
||||
|
||||
const { scale, sort, sortBy, waterfallWidth } = this.props;
|
||||
let sorted, sortedTitle;
|
||||
const active = sort.type == name ? true : undefined;
|
||||
|
||||
if (active) {
|
||||
sorted = sort.ascending ? "ascending" : "descending";
|
||||
sortedTitle = L10N.getStr(sort.ascending
|
||||
? "networkMenu.sortedAsc"
|
||||
: "networkMenu.sortedDesc");
|
||||
}
|
||||
|
||||
// If the pref for this column width exists, set the style
|
||||
// otherwise use default.
|
||||
let colWidth = DEFAULT_COLUMN_WIDTH;
|
||||
if (columnsData.has(name)) {
|
||||
const oneColumnEl = columnsData.get(name);
|
||||
colWidth = oneColumnEl.width;
|
||||
}
|
||||
const columnStyle = {
|
||||
width: colWidth + "%",
|
||||
};
|
||||
|
||||
// Support for columns resizing is currently hidden behind a pref.
|
||||
const draggable = RESIZE_COLUMNS ? Draggable({
|
||||
className: "column-resizer ",
|
||||
onStart: () => this.onStartMove(),
|
||||
onStop: () => this.onStopMove(),
|
||||
onMove: (x) => this.onMove(name, x),
|
||||
}) : undefined;
|
||||
|
||||
return (
|
||||
dom.td({
|
||||
id: `requests-list-${boxName}-header-box`,
|
||||
className: `requests-list-column requests-list-${boxName}`,
|
||||
style: columnStyle,
|
||||
key: name,
|
||||
ref: `${name}Header`,
|
||||
// Used to style the next column.
|
||||
"data-active": active,
|
||||
},
|
||||
button({
|
||||
id: `requests-list-${name}-button`,
|
||||
className: `requests-list-header-button`,
|
||||
"data-sorted": sorted,
|
||||
title: sortedTitle ? `${label} (${sortedTitle})` : label,
|
||||
onClick: () => sortBy(name),
|
||||
},
|
||||
name === "waterfall"
|
||||
? this.waterfallLabel(waterfallWidth, scale, label)
|
||||
: div({ className: "button-text" }, label),
|
||||
div({ className: "button-icon" })
|
||||
),
|
||||
(name !== lastVisibleColumn) && draggable
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render all columns in the table header
|
||||
*/
|
||||
renderColumns() {
|
||||
const visibleColumns = this.getVisibleColumns();
|
||||
return visibleColumns.map(header => this.renderColumn(header));
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
dom.thead({ className: "devtools-toolbar requests-list-headers-group" },
|
||||
dom.tr({
|
||||
className: "requests-list-headers",
|
||||
onContextMenu: this.onContextMenu,
|
||||
ref: node => {
|
||||
this.requestListHeader = node;
|
||||
},
|
||||
},
|
||||
HEADERS.filter((header) => columns[header.name]).map((header) => {
|
||||
const name = header.name;
|
||||
const boxName = header.boxName || name;
|
||||
const label = header.noLocalization
|
||||
? name : L10N.getStr(`netmonitor.toolbar.${header.label || name}`);
|
||||
let sorted, sortedTitle;
|
||||
const active = sort.type == name ? true : undefined;
|
||||
|
||||
if (active) {
|
||||
sorted = sort.ascending ? "ascending" : "descending";
|
||||
sortedTitle = L10N.getStr(sort.ascending
|
||||
? "networkMenu.sortedAsc"
|
||||
: "networkMenu.sortedDesc");
|
||||
}
|
||||
|
||||
return (
|
||||
dom.td({
|
||||
id: `requests-list-${boxName}-header-box`,
|
||||
className: `requests-list-column requests-list-${boxName}`,
|
||||
key: name,
|
||||
ref: `${name}Header`,
|
||||
// Used to style the next column.
|
||||
"data-active": active,
|
||||
},
|
||||
button({
|
||||
id: `requests-list-${name}-button`,
|
||||
className: `requests-list-header-button`,
|
||||
"data-sorted": sorted,
|
||||
title: sortedTitle ? `${label} (${sortedTitle})` : label,
|
||||
onClick: () => sortBy(name),
|
||||
},
|
||||
name === "waterfall"
|
||||
? this.waterfallLabel(waterfallWidth, scale, label)
|
||||
: div({ className: "button-text" }, label),
|
||||
div({ className: "button-icon" })
|
||||
)
|
||||
)
|
||||
);
|
||||
})
|
||||
this.renderColumns(),
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -220,6 +570,7 @@ class RequestListHeader extends Component {
|
|||
module.exports = connect(
|
||||
(state) => ({
|
||||
columns: state.ui.columns,
|
||||
columnsData: state.ui.columnsData,
|
||||
firstRequestStartedMillis: state.requests.firstStartedMillis,
|
||||
scale: getWaterfallScale(state),
|
||||
sort: state.sort,
|
||||
|
@ -231,5 +582,6 @@ module.exports = connect(
|
|||
resizeWaterfall: (width) => dispatch(Actions.resizeWaterfall(width)),
|
||||
sortBy: (type) => dispatch(Actions.sortBy(type)),
|
||||
toggleColumn: (column) => dispatch(Actions.toggleColumn(column)),
|
||||
setColumnsWidth: (widths) => dispatch(Actions.setColumnsWidth(widths)),
|
||||
})
|
||||
)(RequestListHeader);
|
||||
|
|
|
@ -30,6 +30,7 @@ const actionTypes = {
|
|||
TOGGLE_REQUEST_FILTER_TYPE: "TOGGLE_REQUEST_FILTER_TYPE",
|
||||
UPDATE_REQUEST: "UPDATE_REQUEST",
|
||||
WATERFALL_RESIZE: "WATERFALL_RESIZE",
|
||||
SET_COLUMNS_WIDTH: "SET_COLUMNS_WIDTH",
|
||||
};
|
||||
|
||||
// Descriptions for what this frontend is currently doing.
|
||||
|
@ -332,6 +333,11 @@ const TIMING_KEYS = [
|
|||
"receive",
|
||||
];
|
||||
|
||||
// Minimal width of Network Monitor column is 30px, for Waterfall 150px
|
||||
// Default width of columns (which are not defined in DEFAULT_COLUMNS_DATA) is 8%
|
||||
const MIN_COLUMN_WIDTH = 30; // in px
|
||||
const DEFAULT_COLUMN_WIDTH = 8; // in %
|
||||
|
||||
const general = {
|
||||
ACTIVITY_TYPE,
|
||||
EVENTS,
|
||||
|
@ -344,6 +350,8 @@ const general = {
|
|||
REQUESTS_WATERFALL,
|
||||
PANELS,
|
||||
TIMING_KEYS,
|
||||
MIN_COLUMN_WIDTH,
|
||||
DEFAULT_COLUMN_WIDTH,
|
||||
};
|
||||
|
||||
// flatten constants
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
const Services = require("Services");
|
||||
const { applyMiddleware, createStore } = require("devtools/client/shared/vendor/redux");
|
||||
|
||||
const {
|
||||
MIN_COLUMN_WIDTH,
|
||||
DEFAULT_COLUMN_WIDTH,
|
||||
} = require("./constants");
|
||||
|
||||
// Middleware
|
||||
const batching = require("./middleware/batching");
|
||||
const prefs = require("./middleware/prefs");
|
||||
|
@ -21,7 +26,7 @@ const { FilterTypes, Filters } = require("./reducers/filters");
|
|||
const { Requests } = require("./reducers/requests");
|
||||
const { Sort } = require("./reducers/sort");
|
||||
const { TimingMarkers } = require("./reducers/timing-markers");
|
||||
const { UI, Columns } = require("./reducers/ui");
|
||||
const { UI, Columns, ColumnsData } = require("./reducers/ui");
|
||||
|
||||
/**
|
||||
* Configure state and middleware for the Network monitor tool.
|
||||
|
@ -37,6 +42,7 @@ function configureStore(connector, telemetry) {
|
|||
timingMarkers: new TimingMarkers(),
|
||||
ui: UI({
|
||||
columns: getColumnState(),
|
||||
columnsData: getColumnsData(),
|
||||
}),
|
||||
};
|
||||
|
||||
|
@ -70,6 +76,27 @@ function getColumnState() {
|
|||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get columns data (width, min-width)
|
||||
*/
|
||||
function getColumnsData() {
|
||||
const columnsData = getPref("devtools.netmonitor.columnsData");
|
||||
if (!columnsData.length) {
|
||||
return ColumnsData();
|
||||
}
|
||||
|
||||
const newMap = new Map();
|
||||
columnsData.forEach(col => {
|
||||
if (col.name) {
|
||||
col.minWidth = col.minWidth ? col.minWidth : MIN_COLUMN_WIDTH;
|
||||
col.width = col.width ? col.width : DEFAULT_COLUMN_WIDTH;
|
||||
newMap.set(col.name, col);
|
||||
}
|
||||
});
|
||||
|
||||
return newMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filter state from preferences.
|
||||
*/
|
||||
|
|
|
@ -12,6 +12,7 @@ const {
|
|||
TOGGLE_REQUEST_FILTER_TYPE,
|
||||
ENABLE_PERSISTENT_LOGS,
|
||||
DISABLE_BROWSER_CACHE,
|
||||
SET_COLUMNS_WIDTH,
|
||||
} = require("../constants");
|
||||
|
||||
/**
|
||||
|
@ -40,20 +41,45 @@ function prefsMiddleware(store) {
|
|||
"devtools.cache.disabled", store.getState().ui.browserCacheDisabled);
|
||||
break;
|
||||
case TOGGLE_COLUMN:
|
||||
persistVisibleColumns(store.getState());
|
||||
break;
|
||||
case RESET_COLUMNS:
|
||||
const visibleColumns = [];
|
||||
const columns = store.getState().ui.columns;
|
||||
for (const column in columns) {
|
||||
if (columns[column]) {
|
||||
visibleColumns.push(column);
|
||||
}
|
||||
}
|
||||
Services.prefs.setCharPref(
|
||||
"devtools.netmonitor.visibleColumns", JSON.stringify(visibleColumns));
|
||||
persistVisibleColumns(store.getState());
|
||||
persistColumnsData(store.getState());
|
||||
break;
|
||||
case SET_COLUMNS_WIDTH:
|
||||
persistColumnsData(store.getState());
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Store list of visible columns into preferences.
|
||||
*/
|
||||
function persistVisibleColumns(state) {
|
||||
const visibleColumns = [];
|
||||
const columns = state.ui.columns;
|
||||
for (const column in columns) {
|
||||
if (columns[column]) {
|
||||
visibleColumns.push(column);
|
||||
}
|
||||
}
|
||||
|
||||
Services.prefs.setCharPref(
|
||||
"devtools.netmonitor.visibleColumns",
|
||||
JSON.stringify(visibleColumns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store columns data (width, min-width, etc.) into preferences.
|
||||
*/
|
||||
function persistColumnsData(state) {
|
||||
const columnsData = [...state.ui.columnsData.values()];
|
||||
Services.prefs.setCharPref(
|
||||
"devtools.netmonitor.columnsData",
|
||||
JSON.stringify(columnsData));
|
||||
}
|
||||
|
||||
module.exports = prefsMiddleware;
|
||||
|
|
|
@ -21,6 +21,8 @@ const {
|
|||
TOGGLE_COLUMN,
|
||||
WATERFALL_RESIZE,
|
||||
PANELS,
|
||||
MIN_COLUMN_WIDTH,
|
||||
SET_COLUMNS_WIDTH,
|
||||
} = require("../constants");
|
||||
|
||||
const cols = {
|
||||
|
@ -44,6 +46,7 @@ const cols = {
|
|||
latency: false,
|
||||
waterfall: true,
|
||||
};
|
||||
|
||||
function Columns() {
|
||||
return Object.assign(
|
||||
cols,
|
||||
|
@ -51,9 +54,17 @@ function Columns() {
|
|||
);
|
||||
}
|
||||
|
||||
function ColumnsData() {
|
||||
const defaultColumnsData = JSON.parse(
|
||||
Services.prefs.getDefaultBranch(null).getCharPref("devtools.netmonitor.columnsData")
|
||||
);
|
||||
return new Map(defaultColumnsData.map(i => [i.name, i]));
|
||||
}
|
||||
|
||||
function UI(initialState = {}) {
|
||||
return {
|
||||
columns: Columns(),
|
||||
columnsData: ColumnsData(),
|
||||
detailsPanelSelectedTab: PANELS.HEADERS,
|
||||
networkDetailsOpen: false,
|
||||
networkDetailsWidth: null,
|
||||
|
@ -70,6 +81,7 @@ function resetColumns(state) {
|
|||
return {
|
||||
...state,
|
||||
columns: Columns(),
|
||||
columnsData: ColumnsData(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -139,6 +151,30 @@ function toggleColumn(state, action) {
|
|||
};
|
||||
}
|
||||
|
||||
function setColumnsWidth(state, action) {
|
||||
const { widths } = action;
|
||||
const columnsData = new Map(state.columnsData);
|
||||
|
||||
widths.forEach(col => {
|
||||
let data = columnsData.get(col.name);
|
||||
if (!data) {
|
||||
data = {
|
||||
name: col.name,
|
||||
minWidth: MIN_COLUMN_WIDTH,
|
||||
};
|
||||
}
|
||||
columnsData.set(col.name, {
|
||||
...data,
|
||||
width: col.width,
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
...state,
|
||||
columnsData: columnsData,
|
||||
};
|
||||
}
|
||||
|
||||
function ui(state = UI(), action) {
|
||||
switch (action.type) {
|
||||
case CLEAR_REQUESTS:
|
||||
|
@ -167,6 +203,8 @@ function ui(state = UI(), action) {
|
|||
return toggleColumn(state, action);
|
||||
case WATERFALL_RESIZE:
|
||||
return resizeWaterfall(state, action);
|
||||
case SET_COLUMNS_WIDTH:
|
||||
return setColumnsWidth(state, action);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -174,6 +212,7 @@ function ui(state = UI(), action) {
|
|||
|
||||
module.exports = {
|
||||
Columns,
|
||||
ColumnsData,
|
||||
UI,
|
||||
ui,
|
||||
};
|
||||
|
|
|
@ -13,5 +13,6 @@ exports.Prefs = new PrefsHelper("devtools.netmonitor", {
|
|||
networkDetailsWidth: ["Int", "panes-network-details-width"],
|
||||
networkDetailsHeight: ["Int", "panes-network-details-height"],
|
||||
visibleColumns: ["Json", "visibleColumns"],
|
||||
columnsData: ["Json", "columnsData"],
|
||||
filters: ["Json", "filters"],
|
||||
});
|
||||
|
|
|
@ -135,6 +135,7 @@ skip-if = (os == 'mac') || (os == 'win' && os_version == '10.0') # Bug 1479782
|
|||
[browser_net_headers-alignment.js]
|
||||
[browser_net_headers_filter.js]
|
||||
[browser_net_headers_sorted.js]
|
||||
[browser_net_headers-resize.js]
|
||||
[browser_net_image-tooltip.js]
|
||||
[browser_net_json-b64.js]
|
||||
[browser_net_json-empty.js]
|
||||
|
|
|
@ -4,14 +4,21 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests that last visible column can't be hidden
|
||||
* Tests that last visible column can't be hidden. Note that the column
|
||||
* header is visible only if there are requests in the list.
|
||||
*/
|
||||
|
||||
add_task(async function() {
|
||||
const { monitor } = await initNetMonitor(SIMPLE_URL);
|
||||
const { monitor, tab } = await initNetMonitor(SIMPLE_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
const { document, store, parent } = monitor.panelWin;
|
||||
const { document, store, parent, windowRequire } = monitor.panelWin;
|
||||
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
|
||||
store.dispatch(Actions.batchEnable(false));
|
||||
|
||||
const wait = waitForNetworkEvents(monitor, 1);
|
||||
tab.linkedBrowser.reload();
|
||||
await wait;
|
||||
|
||||
const initialColumns = store.getState().ui.columns;
|
||||
for (const column in initialColumns) {
|
||||
|
|
|
@ -4,17 +4,24 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests if visible columns are properly saved
|
||||
* Tests if visible columns are properly saved. Note that the column
|
||||
* header is visible only if there are requests in the list.
|
||||
*/
|
||||
|
||||
add_task(async function() {
|
||||
Services.prefs.setCharPref("devtools.netmonitor.visibleColumns",
|
||||
'["status", "contentSize", "waterfall"]');
|
||||
|
||||
const { monitor } = await initNetMonitor(SIMPLE_URL);
|
||||
const { monitor, tab } = await initNetMonitor(SIMPLE_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
const { document } = monitor.panelWin;
|
||||
const { document, store, windowRequire } = monitor.panelWin;
|
||||
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
|
||||
store.dispatch(Actions.batchEnable(false));
|
||||
|
||||
const wait = waitForNetworkEvents(monitor, 1);
|
||||
tab.linkedBrowser.reload();
|
||||
await wait;
|
||||
|
||||
ok(document.querySelector("#requests-list-status-button"),
|
||||
"Status column should be shown");
|
||||
|
|
|
@ -4,16 +4,23 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests reset column menu item
|
||||
* Tests reset column menu item. Note that the column
|
||||
* header is visible only if there are requests in the list.
|
||||
*/
|
||||
add_task(async function() {
|
||||
const { monitor } = await initNetMonitor(SIMPLE_URL);
|
||||
const { monitor, tab } = await initNetMonitor(SIMPLE_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
const { document, parent, windowRequire } = monitor.panelWin;
|
||||
const { document, store, parent, windowRequire } = monitor.panelWin;
|
||||
const { Prefs } = windowRequire("devtools/client/netmonitor/src/utils/prefs");
|
||||
|
||||
const prefBefore = Prefs.visibleColumns;
|
||||
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
|
||||
store.dispatch(Actions.batchEnable(false));
|
||||
|
||||
const wait = waitForNetworkEvents(monitor, 1);
|
||||
tab.linkedBrowser.reload();
|
||||
await wait;
|
||||
|
||||
await hideColumn(monitor, "status");
|
||||
await hideColumn(monitor, "waterfall");
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests for timings columns.
|
||||
* Tests for timings columns. Note that the column
|
||||
* header is visible only if there are requests in the list.
|
||||
*/
|
||||
add_task(async function() {
|
||||
const { tab, monitor } = await initNetMonitor(SIMPLE_URL);
|
||||
|
@ -16,6 +17,10 @@ add_task(async function() {
|
|||
|
||||
const visibleColumns = store.getState().ui.columns;
|
||||
|
||||
const wait = waitForNetworkEvents(monitor, 1);
|
||||
tab.linkedBrowser.reload();
|
||||
await wait;
|
||||
|
||||
// Hide the waterfall column to make sure timing data are fetched
|
||||
// by the other timing columns ("endTime", "responseTime", "duration",
|
||||
// "latency").
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests resizing of columns in NetMonitor.
|
||||
*/
|
||||
add_task(async function() {
|
||||
// Reset visibleColumns so we only get the default ones
|
||||
// and not all that are set in head.js
|
||||
Services.prefs.clearUserPref("devtools.netmonitor.visibleColumns");
|
||||
let visibleColumns = JSON.parse(
|
||||
Services.prefs.getCharPref("devtools.netmonitor.visibleColumns")
|
||||
);
|
||||
|
||||
// Init network monitor
|
||||
const { tab, monitor } = await initNetMonitor(SIMPLE_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
const { document, windowRequire, store } = monitor.panelWin;
|
||||
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
|
||||
store.dispatch(Actions.batchEnable(false));
|
||||
|
||||
// Wait for network events (to have some requests in the table)
|
||||
const wait = waitForNetworkEvents(monitor, 1);
|
||||
tab.linkedBrowser.reload();
|
||||
await wait;
|
||||
|
||||
const headers = document.querySelector(".requests-list-headers");
|
||||
const parentWidth = headers.getBoundingClientRect().width;
|
||||
|
||||
// 1. Change File column from 25% (default) to 20%
|
||||
// Size column should then change from 5% (default) to 10%
|
||||
// When File width changes, contentSize should compensate the change.
|
||||
info("Resize file & check changed prefs...");
|
||||
const fileHeader = document.querySelector(`#requests-list-file-header-box`);
|
||||
|
||||
resizeColumn(fileHeader, 20, parentWidth);
|
||||
|
||||
// after resize - get fresh prefs for tests
|
||||
let columnsData = JSON.parse(
|
||||
Services.prefs.getCharPref("devtools.netmonitor.columnsData")
|
||||
);
|
||||
checkColumnsData(columnsData, "file", 20);
|
||||
checkColumnsData(columnsData, "contentSize", 10);
|
||||
checkSumOfVisibleColumns(columnsData, visibleColumns);
|
||||
|
||||
// 2. Change Waterfall column width and check that the size
|
||||
// of waterfall changed correctly and all the other columns changed size.
|
||||
info("Resize waterfall & check changed prefs...");
|
||||
const waterfallHeader = document.querySelector(`#requests-list-waterfall-header-box`);
|
||||
// before resizing waterfall -> save old columnsData for later testing
|
||||
const oldColumnsData = JSON.parse(
|
||||
Services.prefs.getCharPref("devtools.netmonitor.columnsData")
|
||||
);
|
||||
resizeWaterfallColumn(waterfallHeader, 30, parentWidth); // 30 fails currently!
|
||||
|
||||
// after resize - get fresh prefs for tests
|
||||
columnsData = JSON.parse(
|
||||
Services.prefs.getCharPref("devtools.netmonitor.columnsData")
|
||||
);
|
||||
|
||||
checkColumnsData(columnsData, "waterfall", 30);
|
||||
checkSumOfVisibleColumns(columnsData, visibleColumns);
|
||||
checkAllColumnsChanged(columnsData, oldColumnsData, visibleColumns);
|
||||
|
||||
// 3. Check that all rows have the right column sizes.
|
||||
info("Checking alignment of columns and headers...");
|
||||
const requestsContainer = document.querySelector(".requests-list-row-group");
|
||||
testColumnsAlignment(headers, requestsContainer);
|
||||
|
||||
// 4. Hide all columns but size and waterfall
|
||||
// and check that they resize correctly. Then resize
|
||||
// waterfall to 50% => size should take up 50%
|
||||
info("Hide all but 2 columns - size & waterfall and check resizing...");
|
||||
await hideMoreColumns(monitor,
|
||||
["status", "method", "domain", "file", "cause", "type", "transferred"]);
|
||||
|
||||
resizeWaterfallColumn(waterfallHeader, 50, parentWidth);
|
||||
// after resize - get fresh prefs for tests
|
||||
columnsData = JSON.parse(
|
||||
Services.prefs.getCharPref("devtools.netmonitor.columnsData")
|
||||
);
|
||||
visibleColumns = JSON.parse(
|
||||
Services.prefs.getCharPref("devtools.netmonitor.visibleColumns")
|
||||
);
|
||||
|
||||
checkColumnsData(columnsData, "contentSize", 50);
|
||||
checkColumnsData(columnsData, "waterfall", 50);
|
||||
checkSumOfVisibleColumns(columnsData, visibleColumns);
|
||||
|
||||
// 5. Hide all columns but domain and file
|
||||
// and resize domain to 50% => file should be 50%
|
||||
info("Hide all but 2 columns - domain & file and check resizing...");
|
||||
await showMoreColumns(monitor, ["domain", "file"]);
|
||||
await hideMoreColumns(monitor, ["contentSize", "waterfall"]);
|
||||
|
||||
const domainHeader = document.querySelector(`#requests-list-domain-header-box`);
|
||||
resizeColumn(domainHeader, 50, parentWidth);
|
||||
|
||||
// after resize - get fresh prefs for tests
|
||||
columnsData = JSON.parse(
|
||||
Services.prefs.getCharPref("devtools.netmonitor.columnsData")
|
||||
);
|
||||
|
||||
visibleColumns = JSON.parse(
|
||||
Services.prefs.getCharPref("devtools.netmonitor.visibleColumns")
|
||||
);
|
||||
|
||||
checkColumnsData(columnsData, "domain", 50);
|
||||
checkColumnsData(columnsData, "file", 50);
|
||||
checkSumOfVisibleColumns(columnsData, visibleColumns);
|
||||
|
||||
// Done: clean up.
|
||||
return teardown(monitor);
|
||||
});
|
||||
|
||||
async function hideMoreColumns(monitor, arr) {
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
await hideColumn(monitor, arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
async function showMoreColumns(monitor, arr) {
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
await showColumn(monitor, arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function resizeColumn(columnHeader, newPercent, parentWidth) {
|
||||
const newWidthInPixels = newPercent * parentWidth / 100;
|
||||
const win = columnHeader.ownerDocument.defaultView;
|
||||
const mouseDown = columnHeader.getBoundingClientRect().width;
|
||||
const mouseMove = newWidthInPixels;
|
||||
|
||||
EventUtils.synthesizeMouse(columnHeader, mouseDown, 1, { type: "mousedown" }, win);
|
||||
EventUtils.synthesizeMouse(columnHeader, mouseMove, 1, { type: "mousemove" }, win);
|
||||
EventUtils.synthesizeMouse(columnHeader, mouseMove, 1, { type: "mouseup" }, win);
|
||||
}
|
||||
|
||||
function resizeWaterfallColumn(columnHeader, newPercent, parentWidth) {
|
||||
const newWidthInPixels = newPercent * parentWidth / 100;
|
||||
const win = columnHeader.ownerDocument.defaultView;
|
||||
const mouseDown = columnHeader.getBoundingClientRect().left;
|
||||
const mouseMove =
|
||||
mouseDown + (columnHeader.getBoundingClientRect().width - newWidthInPixels);
|
||||
|
||||
EventUtils.synthesizeMouse(
|
||||
columnHeader.parentElement, mouseDown, 1, { type: "mousedown" }, win);
|
||||
EventUtils.synthesizeMouse(
|
||||
columnHeader.parentElement, mouseMove, 1, { type: "mousemove" }, win);
|
||||
EventUtils.synthesizeMouse(
|
||||
columnHeader.parentElement, mouseMove, 1, { type: "mouseup" }, win);
|
||||
}
|
||||
|
||||
function checkColumnsData(columnsData, column, expectedWidth) {
|
||||
const widthInPref = Math.round(getWidthFromPref(columnsData, column));
|
||||
is(widthInPref, expectedWidth, "Column " + column + " has expected size.");
|
||||
}
|
||||
|
||||
function checkSumOfVisibleColumns(columnsData, visibleColumns) {
|
||||
let sum = 0;
|
||||
visibleColumns.forEach(column => {
|
||||
sum += getWidthFromPref(columnsData, column);
|
||||
});
|
||||
sum = Math.round(sum);
|
||||
is(sum, 100, "All visible columns cover 100%.");
|
||||
}
|
||||
|
||||
function getWidthFromPref(columnsData, column) {
|
||||
const widthInPref = columnsData.find(function(element) {
|
||||
return element.name === column;
|
||||
}).width;
|
||||
return widthInPref;
|
||||
}
|
||||
|
||||
function checkAllColumnsChanged(columnsData, oldColumnsData, visibleColumns) {
|
||||
const oldWaterfallWidth = getWidthFromPref(oldColumnsData, "waterfall");
|
||||
const newWaterfallWidth = getWidthFromPref(columnsData, "waterfall");
|
||||
visibleColumns.forEach(column => {
|
||||
// do not test waterfall against waterfall
|
||||
if (column !== "waterfall") {
|
||||
const oldWidth = getWidthFromPref(oldColumnsData, column);
|
||||
const newWidth = getWidthFromPref(columnsData, column);
|
||||
|
||||
// Test that if waterfall is smaller all other columns are bigger
|
||||
if (oldWaterfallWidth > newWaterfallWidth) {
|
||||
is(oldWidth < newWidth, true,
|
||||
"Column " + column + " has changed width correctly.");
|
||||
}
|
||||
// Test that if waterfall is bigger all other columns are smaller
|
||||
if (oldWaterfallWidth < newWaterfallWidth) {
|
||||
is(oldWidth > newWidth, true,
|
||||
"Column " + column + " has changed width correctly.");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
|
@ -118,16 +118,34 @@ Services.prefs.setCharPref(
|
|||
"\"startTime\",\"status\",\"transferred\",\"type\",\"waterfall\"]"
|
||||
);
|
||||
|
||||
Services.prefs.setCharPref("devtools.netmonitor.columnsData",
|
||||
'[{"name":"status","minWidth":30,"width":5},' +
|
||||
'{"name":"method","minWidth":30,"width":5},' +
|
||||
'{"name":"domain","minWidth":30,"width":10},' +
|
||||
'{"name":"file","minWidth":30,"width":25},' +
|
||||
'{"name":"cause","minWidth":30,"width":10},' +
|
||||
'{"name":"type","minWidth":30,"width":5},' +
|
||||
'{"name":"transferred","minWidth":30,"width":10},' +
|
||||
'{"name":"contentSize","minWidth":30,"width":5},' +
|
||||
'{"name":"waterfall","minWidth":150,"width":25}]');
|
||||
|
||||
// Increase UI limit for responses rendered using CodeMirror in tests.
|
||||
Services.prefs.setIntPref("devtools.netmonitor.response.ui.limit", 1024 * 105);
|
||||
|
||||
// Support for columns resizing is currently hidden behind this pref,
|
||||
// but testing is on
|
||||
Services.prefs.setBoolPref("devtools.netmonitor.features.resizeColumns", true);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
info("finish() was called, cleaning up...");
|
||||
|
||||
Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
|
||||
Services.prefs.setCharPref("devtools.netmonitor.filters", gDefaultFilters);
|
||||
Services.prefs.clearUserPref("devtools.cache.disabled");
|
||||
Services.prefs.clearUserPref("devtools.netmonitor.columnsData");
|
||||
Services.prefs.clearUserPref("devtools.netmonitor.response.ui.limit");
|
||||
Services.prefs.clearUserPref("devtools.netmonitor.visibleColumns");
|
||||
Services.prefs.clearUserPref("devtools.netmonitor.features.resizeColumns");
|
||||
Services.cookies.removeAll();
|
||||
});
|
||||
|
||||
|
|
|
@ -175,6 +175,12 @@ pref("devtools.netmonitor.filters", "[\"all\"]");
|
|||
pref("devtools.netmonitor.visibleColumns",
|
||||
"[\"status\",\"method\",\"domain\",\"file\",\"cause\",\"type\",\"transferred\",\"contentSize\",\"waterfall\"]"
|
||||
);
|
||||
pref("devtools.netmonitor.columnsData",
|
||||
'[{"name":"status","minWidth":30,"width":5}, {"name":"method","minWidth":30,"width":5}, {"name":"domain","minWidth":30,"width":10}, {"name":"file","minWidth":30,"width":25}, {"name":"cause","minWidth":30,"width":10},{"name":"type","minWidth":30,"width":5},{"name":"transferred","minWidth":30,"width":10},{"name":"contentSize","minWidth":30,"width":5},{"name":"waterfall","minWidth":150,"width":25}]');
|
||||
|
||||
// Support for columns resizing is currently hidden behind this pref.
|
||||
pref("devtools.netmonitor.features.resizeColumns", false);
|
||||
|
||||
pref("devtools.netmonitor.response.ui.limit", 10240);
|
||||
|
||||
// Save request/response bodies yes/no.
|
||||
|
|
Загрузка…
Ссылка в новой задаче