mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-28 12:45:27 +00:00
Bug 1356126 - Move column react component to separate files;r=rickychien
MozReview-Commit-ID: HdLcKOHW0ag --HG-- extra : rebase_source : b76852580f453cc45c3e408ec9827f870347d2b7
This commit is contained in:
parent
06d3c649d5
commit
0a273175e9
@ -12,6 +12,17 @@ DevToolsModules(
|
||||
'network-details-panel.js',
|
||||
'params-panel.js',
|
||||
'properties-view.js',
|
||||
'request-list-column-cause.js',
|
||||
'request-list-column-content-size.js',
|
||||
'request-list-column-domain.js',
|
||||
'request-list-column-file.js',
|
||||
'request-list-column-method.js',
|
||||
'request-list-column-protocol.js',
|
||||
'request-list-column-remote-ip.js',
|
||||
'request-list-column-status.js',
|
||||
'request-list-column-transferred-size.js',
|
||||
'request-list-column-type.js',
|
||||
'request-list-column-waterfall.js',
|
||||
'request-list-content.js',
|
||||
'request-list-empty-notice.js',
|
||||
'request-list-header.js',
|
||||
|
@ -0,0 +1,62 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
|
||||
const { div, span } = DOM;
|
||||
|
||||
const RequestListColumnCause = createClass({
|
||||
displayName: "RequestListColumnCause",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
onCauseBadgeClick: PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.cause !== nextProps.item.cause;
|
||||
},
|
||||
|
||||
render() {
|
||||
const {
|
||||
item,
|
||||
onCauseBadgeClick,
|
||||
} = this.props;
|
||||
|
||||
const { cause } = item;
|
||||
|
||||
let causeType = "";
|
||||
let causeUri = undefined;
|
||||
let causeHasStack = false;
|
||||
|
||||
if (cause) {
|
||||
// Legacy server might send a numeric value. Display it as "unknown"
|
||||
causeType = typeof cause.type === "string" ? cause.type : "unknown";
|
||||
causeUri = cause.loadingDocumentUri;
|
||||
causeHasStack = cause.stacktrace && cause.stacktrace.length > 0;
|
||||
}
|
||||
|
||||
return (
|
||||
div({
|
||||
className: "requests-list-subitem requests-list-cause",
|
||||
title: causeUri,
|
||||
},
|
||||
span({
|
||||
className: "requests-list-cause-stack",
|
||||
hidden: !causeHasStack,
|
||||
onClick: onCauseBadgeClick,
|
||||
}, "JS"),
|
||||
span({ className: "subitem-label" }, causeType),
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = RequestListColumnCause;
|
@ -0,0 +1,46 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { getFormattedSize } = require("../utils/format-utils");
|
||||
|
||||
const { div, span } = DOM;
|
||||
|
||||
const RequestListColumnContentSize = createClass({
|
||||
displayName: "RequestListColumnContentSize",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.contentSize !== nextProps.item.contentSize;
|
||||
},
|
||||
|
||||
render() {
|
||||
const { contentSize } = this.props.item;
|
||||
|
||||
let text;
|
||||
if (typeof contentSize == "number") {
|
||||
text = getFormattedSize(contentSize);
|
||||
}
|
||||
|
||||
return (
|
||||
div({
|
||||
className: "requests-list-subitem subitem-label requests-list-size",
|
||||
title: text,
|
||||
},
|
||||
span({ className: "subitem-label" }, text),
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = RequestListColumnContentSize;
|
@ -0,0 +1,64 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const { propertiesEqual } = require("../utils/request-utils");
|
||||
|
||||
const { div, span } = DOM;
|
||||
|
||||
const UPDATED_DOMAIN_PROPS = [
|
||||
"urlDetails",
|
||||
"remoteAddress",
|
||||
"securityState",
|
||||
];
|
||||
|
||||
const RequestListColumnDomain = createClass({
|
||||
displayName: "RequestListColumnDomain",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
onSecurityIconClick: PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_DOMAIN_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
|
||||
render() {
|
||||
const { item, onSecurityIconClick } = this.props;
|
||||
const { urlDetails, remoteAddress, securityState } = item;
|
||||
|
||||
let iconClassList = ["requests-security-state-icon"];
|
||||
let iconTitle;
|
||||
if (urlDetails.isLocal) {
|
||||
iconClassList.push("security-state-local");
|
||||
iconTitle = L10N.getStr("netmonitor.security.state.secure");
|
||||
} else if (securityState) {
|
||||
iconClassList.push(`security-state-${securityState}`);
|
||||
iconTitle = L10N.getStr(`netmonitor.security.state.${securityState}`);
|
||||
}
|
||||
|
||||
let title = urlDetails.host + (remoteAddress ? ` (${remoteAddress})` : "");
|
||||
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-security-and-domain" },
|
||||
div({
|
||||
className: iconClassList.join(" "),
|
||||
title: iconTitle,
|
||||
onClick: onSecurityIconClick,
|
||||
}),
|
||||
span({ className: "subitem-label requests-list-domain", title }, urlDetails.host),
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = RequestListColumnDomain;
|
@ -0,0 +1,54 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { propertiesEqual } = require("../utils/request-utils");
|
||||
|
||||
const { div, img } = DOM;
|
||||
|
||||
const UPDATED_FILE_PROPS = [
|
||||
"urlDetails",
|
||||
"responseContentDataUri",
|
||||
];
|
||||
|
||||
const RequestListColumnFile = createClass({
|
||||
displayName: "RequestListColumnFile",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_FILE_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
|
||||
render() {
|
||||
const { urlDetails, responseContentDataUri } = this.props.item;
|
||||
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-icon-and-file" },
|
||||
img({
|
||||
className: "requests-list-icon",
|
||||
src: responseContentDataUri,
|
||||
hidden: !responseContentDataUri,
|
||||
"data-type": responseContentDataUri ? "thumbnail" : undefined,
|
||||
}),
|
||||
div({
|
||||
className: "subitem-label requests-list-file",
|
||||
title: urlDetails.unicodeUrl,
|
||||
},
|
||||
urlDetails.baseNameWithQuery,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = RequestListColumnFile;
|
@ -0,0 +1,36 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
|
||||
const { div, span } = DOM;
|
||||
|
||||
const RequestListColumnMethod = createClass({
|
||||
displayName: "RequestListColumnMethod",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.method !== nextProps.item.method;
|
||||
},
|
||||
|
||||
render() {
|
||||
const { method } = this.props.item;
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-method-box" },
|
||||
span({ className: "subitem-label requests-list-method" }, method)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = RequestListColumnMethod;
|
@ -0,0 +1,36 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
|
||||
const { div, span } = DOM;
|
||||
|
||||
const RequestListColumnProtocol = createClass({
|
||||
displayName: "RequestListColumnProtocol",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.httpVersion !== nextProps.item.httpVersion;
|
||||
},
|
||||
|
||||
render() {
|
||||
const { httpVersion } = this.props.item;
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-protocol" },
|
||||
span({ className: "subitem-label", title: httpVersion }, httpVersion),
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = RequestListColumnProtocol;
|
@ -0,0 +1,38 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
|
||||
const { div, span } = DOM;
|
||||
|
||||
const RequestListColumnRemoteIP = createClass({
|
||||
displayName: "RequestListColumnRemoteIP",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.remoteAddress !== nextProps.item.remoteAddress;
|
||||
},
|
||||
|
||||
render() {
|
||||
const { remoteAddress, remotePort } = this.props.item;
|
||||
let remoteSummary = remoteAddress ? `${remoteAddress}:${remotePort}` : "";
|
||||
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-remoteip" },
|
||||
span({ className: "subitem-label", title: remoteSummary }, remoteSummary),
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = RequestListColumnRemoteIP;
|
@ -0,0 +1,68 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { propertiesEqual } = require("../utils/request-utils");
|
||||
|
||||
const { div, span } = DOM;
|
||||
|
||||
const UPDATED_STATUS_PROPS = [
|
||||
"fromCache",
|
||||
"fromServiceWorker",
|
||||
"status",
|
||||
"statusText",
|
||||
];
|
||||
|
||||
const RequestListColumnStatus = createClass({
|
||||
displayName: "RequestListColumnStatus",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_STATUS_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
|
||||
render() {
|
||||
const { status, statusText, fromCache, fromServiceWorker } = this.props.item;
|
||||
|
||||
let code, title;
|
||||
|
||||
if (status) {
|
||||
if (fromCache) {
|
||||
code = "cached";
|
||||
} else if (fromServiceWorker) {
|
||||
code = "service worker";
|
||||
} else {
|
||||
code = status;
|
||||
}
|
||||
|
||||
if (statusText) {
|
||||
title = `${status} ${statusText}`;
|
||||
if (fromCache) {
|
||||
title += " (cached)";
|
||||
}
|
||||
if (fromServiceWorker) {
|
||||
title += " (service worker)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-status", title },
|
||||
div({ className: "requests-list-status-icon", "data-code": code }),
|
||||
span({ className: "subitem-label requests-list-status-code" }, status)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = RequestListColumnStatus;
|
@ -0,0 +1,63 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { getFormattedSize } = require("../utils/format-utils");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const { propertiesEqual } = require("../utils/request-utils");
|
||||
|
||||
const { div, span } = DOM;
|
||||
|
||||
const UPDATED_TRANSFERRED_PROPS = [
|
||||
"transferredSize",
|
||||
"fromCache",
|
||||
"fromServiceWorker",
|
||||
];
|
||||
|
||||
const RequestListColumnTransferredSize = createClass({
|
||||
displayName: "RequestListColumnTransferredSize",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_TRANSFERRED_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
|
||||
render() {
|
||||
const { transferredSize, fromCache, fromServiceWorker, status } = this.props.item;
|
||||
|
||||
let text;
|
||||
let className = "subitem-label";
|
||||
if (fromCache || status === "304") {
|
||||
text = L10N.getStr("networkMenu.sizeCached");
|
||||
className += " theme-comment";
|
||||
} else if (fromServiceWorker) {
|
||||
text = L10N.getStr("networkMenu.sizeServiceWorker");
|
||||
className += " theme-comment";
|
||||
} else if (typeof transferredSize == "number") {
|
||||
text = getFormattedSize(transferredSize);
|
||||
} else if (transferredSize === null) {
|
||||
text = L10N.getStr("networkMenu.sizeUnavailable");
|
||||
}
|
||||
|
||||
return (
|
||||
div({
|
||||
className: "requests-list-subitem requests-list-transferred",
|
||||
title: text,
|
||||
},
|
||||
span({ className }, text),
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = RequestListColumnTransferredSize;
|
@ -0,0 +1,52 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { getAbbreviatedMimeType } = require("../utils/request-utils");
|
||||
|
||||
const { div, span } = DOM;
|
||||
|
||||
const CONTENT_MIME_TYPE_ABBREVIATIONS = {
|
||||
"ecmascript": "js",
|
||||
"javascript": "js",
|
||||
"x-javascript": "js"
|
||||
};
|
||||
|
||||
const RequestListColumnType = createClass({
|
||||
displayName: "RequestListColumnType",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.mimeType !== nextProps.item.mimeType;
|
||||
},
|
||||
|
||||
render() {
|
||||
const { mimeType } = this.props.item;
|
||||
let abbrevType;
|
||||
if (mimeType) {
|
||||
abbrevType = getAbbreviatedMimeType(mimeType);
|
||||
abbrevType = CONTENT_MIME_TYPE_ABBREVIATIONS[abbrevType] || abbrevType;
|
||||
}
|
||||
|
||||
return (
|
||||
div({
|
||||
className: "requests-list-subitem requests-list-type",
|
||||
title: mimeType,
|
||||
},
|
||||
span({ className: "subitem-label" }, abbrevType),
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = RequestListColumnType;
|
@ -0,0 +1,95 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const { propertiesEqual } = require("../utils/request-utils");
|
||||
|
||||
const { div } = DOM;
|
||||
|
||||
const UPDATED_WATERFALL_PROPS = [
|
||||
"eventTimings",
|
||||
"totalTime",
|
||||
"fromCache",
|
||||
"fromServiceWorker",
|
||||
];
|
||||
|
||||
const RequestListColumnWaterfall = createClass({
|
||||
displayName: "RequestListColumnWaterfall",
|
||||
|
||||
propTypes: {
|
||||
firstRequestStartedMillis: PropTypes.number.isRequired,
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.firstRequestStartedMillis !== nextProps.firstRequestStartedMillis ||
|
||||
!propertiesEqual(UPDATED_WATERFALL_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
|
||||
render() {
|
||||
const { item, firstRequestStartedMillis } = this.props;
|
||||
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-waterfall" },
|
||||
div({
|
||||
className: "requests-list-timings",
|
||||
style: {
|
||||
paddingInlineStart: `${item.startedMillis - firstRequestStartedMillis}px`,
|
||||
},
|
||||
},
|
||||
timingBoxes(item),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// List of properties of the timing info we want to create boxes for
|
||||
const TIMING_KEYS = ["blocked", "dns", "connect", "send", "wait", "receive"];
|
||||
|
||||
function timingBoxes(item) {
|
||||
const { eventTimings, totalTime, fromCache, fromServiceWorker } = item;
|
||||
let boxes = [];
|
||||
|
||||
if (fromCache || fromServiceWorker) {
|
||||
return boxes;
|
||||
}
|
||||
|
||||
if (eventTimings) {
|
||||
// Add a set of boxes representing timing information.
|
||||
for (let key of TIMING_KEYS) {
|
||||
let width = eventTimings.timings[key];
|
||||
|
||||
// Don't render anything if it surely won't be visible.
|
||||
// One millisecond == one unscaled pixel.
|
||||
if (width > 0) {
|
||||
boxes.push(div({
|
||||
key,
|
||||
className: "requests-list-timings-box " + key,
|
||||
style: { width }
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof totalTime === "number") {
|
||||
let text = L10N.getFormatStr("networkMenu.totalMS", totalTime);
|
||||
boxes.push(div({
|
||||
key: "total",
|
||||
className: "requests-list-timings-total",
|
||||
title: text
|
||||
}, text));
|
||||
}
|
||||
|
||||
return boxes;
|
||||
}
|
||||
|
||||
module.exports = RequestListColumnWaterfall;
|
@ -12,18 +12,22 @@ const {
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const I = require("devtools/client/shared/vendor/immutable");
|
||||
|
||||
const { getFormattedSize } = require("../utils/format-utils");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const { getAbbreviatedMimeType } = require("../utils/request-utils");
|
||||
const { propertiesEqual } = require("../utils/request-utils");
|
||||
|
||||
const { div, img, span } = DOM;
|
||||
// Components
|
||||
const RequestListColumnCause = createFactory(require("./request-list-column-cause"));
|
||||
const RequestListColumnContentSize = createFactory(require("./request-list-column-content-size"));
|
||||
const RequestListColumnDomain = createFactory(require("./request-list-column-domain"));
|
||||
const RequestListColumnFile = createFactory(require("./request-list-column-file"));
|
||||
const RequestListColumnMethod = createFactory(require("./request-list-column-method"));
|
||||
const RequestListColumnProtocol = createFactory(require("./request-list-column-protocol"));
|
||||
const RequestListColumnRemoteIP = createFactory(require("./request-list-column-remote-ip"));
|
||||
const RequestListColumnStatus = createFactory(require("./request-list-column-status"));
|
||||
const RequestListColumnTransferredSize = createFactory(require("./request-list-column-transferred-size"));
|
||||
const RequestListColumnType = createFactory(require("./request-list-column-type"));
|
||||
const RequestListColumnWaterfall = createFactory(require("./request-list-column-waterfall"));
|
||||
|
||||
/**
|
||||
* Compare two objects on a subset of their properties
|
||||
*/
|
||||
function propertiesEqual(props, item1, item2) {
|
||||
return item1 === item2 || props.every(p => item1[p] === item2[p]);
|
||||
}
|
||||
const { div } = DOM;
|
||||
|
||||
/**
|
||||
* Used by shouldComponentUpdate: compare two items, and compare only properties
|
||||
@ -131,458 +135,21 @@ const RequestListItem = createClass({
|
||||
onContextMenu,
|
||||
onMouseDown,
|
||||
},
|
||||
columns.get("status") && StatusColumn({ item }),
|
||||
columns.get("method") && MethodColumn({ item }),
|
||||
columns.get("file") && FileColumn({ item }),
|
||||
columns.get("protocol") && ProtocolColumn({ item }),
|
||||
columns.get("domain") && DomainColumn({ item, onSecurityIconClick }),
|
||||
columns.get("remoteip") && RemoteIPColumn({ item }),
|
||||
columns.get("cause") && CauseColumn({ item, onCauseBadgeClick }),
|
||||
columns.get("type") && TypeColumn({ item }),
|
||||
columns.get("transferred") && TransferredSizeColumn({ item }),
|
||||
columns.get("contentSize") && ContentSizeColumn({ item }),
|
||||
columns.get("waterfall") && WaterfallColumn({ item, firstRequestStartedMillis }),
|
||||
columns.get("status") && RequestListColumnStatus({ item }),
|
||||
columns.get("method") && RequestListColumnMethod({ item }),
|
||||
columns.get("file") && RequestListColumnFile({ item }),
|
||||
columns.get("protocol") && RequestListColumnProtocol({ item }),
|
||||
columns.get("domain") && RequestListColumnDomain({ item, onSecurityIconClick }),
|
||||
columns.get("remoteip") && RequestListColumnRemoteIP({ item }),
|
||||
columns.get("cause") && RequestListColumnCause({ item, onCauseBadgeClick }),
|
||||
columns.get("type") && RequestListColumnType({ item }),
|
||||
columns.get("transferred") && RequestListColumnTransferredSize({ item }),
|
||||
columns.get("contentSize") && RequestListColumnContentSize({ item }),
|
||||
columns.get("waterfall") &&
|
||||
RequestListColumnWaterfall({ item, firstRequestStartedMillis }),
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const UPDATED_STATUS_PROPS = [
|
||||
"status",
|
||||
"statusText",
|
||||
"fromCache",
|
||||
"fromServiceWorker",
|
||||
];
|
||||
|
||||
const StatusColumn = createFactory(createClass({
|
||||
displayName: "StatusColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_STATUS_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
|
||||
render() {
|
||||
const { status, statusText, fromCache, fromServiceWorker } = this.props.item;
|
||||
|
||||
let code, title;
|
||||
|
||||
if (status) {
|
||||
if (fromCache) {
|
||||
code = "cached";
|
||||
} else if (fromServiceWorker) {
|
||||
code = "service worker";
|
||||
} else {
|
||||
code = status;
|
||||
}
|
||||
|
||||
if (statusText) {
|
||||
title = `${status} ${statusText}`;
|
||||
if (fromCache) {
|
||||
title += " (cached)";
|
||||
}
|
||||
if (fromServiceWorker) {
|
||||
title += " (service worker)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-status", title },
|
||||
div({ className: "requests-list-status-icon", "data-code": code }),
|
||||
span({ className: "subitem-label requests-list-status-code" }, status)
|
||||
)
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
||||
const MethodColumn = createFactory(createClass({
|
||||
displayName: "MethodColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.method !== nextProps.item.method;
|
||||
},
|
||||
|
||||
render() {
|
||||
const { method } = this.props.item;
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-method-box" },
|
||||
span({ className: "subitem-label requests-list-method" }, method)
|
||||
)
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
||||
const UPDATED_FILE_PROPS = [
|
||||
"urlDetails",
|
||||
"responseContentDataUri",
|
||||
];
|
||||
|
||||
const FileColumn = createFactory(createClass({
|
||||
displayName: "FileColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_FILE_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
|
||||
render() {
|
||||
const { urlDetails, responseContentDataUri } = this.props.item;
|
||||
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-icon-and-file" },
|
||||
img({
|
||||
className: "requests-list-icon",
|
||||
src: responseContentDataUri,
|
||||
hidden: !responseContentDataUri,
|
||||
"data-type": responseContentDataUri ? "thumbnail" : undefined,
|
||||
}),
|
||||
div({
|
||||
className: "subitem-label requests-list-file",
|
||||
title: urlDetails.unicodeUrl,
|
||||
},
|
||||
urlDetails.baseNameWithQuery,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
||||
const ProtocolColumn = createFactory(createClass({
|
||||
displayName: "Protocol",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.httpVersion !== nextProps.item.httpVersion;
|
||||
},
|
||||
|
||||
render() {
|
||||
const { httpVersion } = this.props.item;
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-protocol" },
|
||||
span({ className: "subitem-label", title: httpVersion }, httpVersion),
|
||||
)
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
||||
const UPDATED_DOMAIN_PROPS = [
|
||||
"urlDetails",
|
||||
"remoteAddress",
|
||||
"securityState",
|
||||
];
|
||||
|
||||
const DomainColumn = createFactory(createClass({
|
||||
displayName: "DomainColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
onSecurityIconClick: PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_DOMAIN_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
|
||||
render() {
|
||||
const { item, onSecurityIconClick } = this.props;
|
||||
const { urlDetails, remoteAddress, securityState } = item;
|
||||
|
||||
let iconClassList = ["requests-security-state-icon"];
|
||||
let iconTitle;
|
||||
if (urlDetails.isLocal) {
|
||||
iconClassList.push("security-state-local");
|
||||
iconTitle = L10N.getStr("netmonitor.security.state.secure");
|
||||
} else if (securityState) {
|
||||
iconClassList.push(`security-state-${securityState}`);
|
||||
iconTitle = L10N.getStr(`netmonitor.security.state.${securityState}`);
|
||||
}
|
||||
|
||||
let title = urlDetails.host + (remoteAddress ? ` (${remoteAddress})` : "");
|
||||
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-security-and-domain" },
|
||||
div({
|
||||
className: iconClassList.join(" "),
|
||||
title: iconTitle,
|
||||
onClick: onSecurityIconClick,
|
||||
}),
|
||||
span({ className: "subitem-label requests-list-domain", title }, urlDetails.host),
|
||||
)
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
||||
const RemoteIPColumn = createFactory(createClass({
|
||||
displayName: "RemoteIP",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.remoteAddress !== nextProps.item.remoteAddress;
|
||||
},
|
||||
|
||||
render() {
|
||||
const { remoteAddress, remotePort } = this.props.item;
|
||||
let remoteSummary = remoteAddress ? `${remoteAddress}:${remotePort}` : "";
|
||||
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-remoteip" },
|
||||
span({ className: "subitem-label", title: remoteSummary }, remoteSummary),
|
||||
)
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
||||
const CauseColumn = createFactory(createClass({
|
||||
displayName: "CauseColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
onCauseBadgeClick: PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.cause !== nextProps.item.cause;
|
||||
},
|
||||
|
||||
render() {
|
||||
const {
|
||||
item,
|
||||
onCauseBadgeClick,
|
||||
} = this.props;
|
||||
|
||||
const { cause } = item;
|
||||
|
||||
let causeType = "";
|
||||
let causeUri = undefined;
|
||||
let causeHasStack = false;
|
||||
|
||||
if (cause) {
|
||||
// Legacy server might send a numeric value. Display it as "unknown"
|
||||
causeType = typeof cause.type === "string" ? cause.type : "unknown";
|
||||
causeUri = cause.loadingDocumentUri;
|
||||
causeHasStack = cause.stacktrace && cause.stacktrace.length > 0;
|
||||
}
|
||||
|
||||
return (
|
||||
div({
|
||||
className: "requests-list-subitem requests-list-cause",
|
||||
title: causeUri,
|
||||
},
|
||||
span({
|
||||
className: "requests-list-cause-stack",
|
||||
hidden: !causeHasStack,
|
||||
onClick: onCauseBadgeClick,
|
||||
}, "JS"),
|
||||
span({ className: "subitem-label" }, causeType),
|
||||
)
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
||||
const CONTENT_MIME_TYPE_ABBREVIATIONS = {
|
||||
"ecmascript": "js",
|
||||
"javascript": "js",
|
||||
"x-javascript": "js"
|
||||
};
|
||||
|
||||
const TypeColumn = createFactory(createClass({
|
||||
displayName: "TypeColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.mimeType !== nextProps.item.mimeType;
|
||||
},
|
||||
|
||||
render() {
|
||||
const { mimeType } = this.props.item;
|
||||
let abbrevType;
|
||||
if (mimeType) {
|
||||
abbrevType = getAbbreviatedMimeType(mimeType);
|
||||
abbrevType = CONTENT_MIME_TYPE_ABBREVIATIONS[abbrevType] || abbrevType;
|
||||
}
|
||||
|
||||
return (
|
||||
div({
|
||||
className: "requests-list-subitem requests-list-type",
|
||||
title: mimeType,
|
||||
},
|
||||
span({ className: "subitem-label" }, abbrevType),
|
||||
)
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
||||
const UPDATED_TRANSFERRED_PROPS = [
|
||||
"transferredSize",
|
||||
"fromCache",
|
||||
"fromServiceWorker",
|
||||
];
|
||||
|
||||
const TransferredSizeColumn = createFactory(createClass({
|
||||
displayName: "TransferredSizeColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_TRANSFERRED_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
|
||||
render() {
|
||||
const { transferredSize, fromCache, fromServiceWorker, status } = this.props.item;
|
||||
|
||||
let text;
|
||||
let className = "subitem-label";
|
||||
if (fromCache || status === "304") {
|
||||
text = L10N.getStr("networkMenu.sizeCached");
|
||||
className += " theme-comment";
|
||||
} else if (fromServiceWorker) {
|
||||
text = L10N.getStr("networkMenu.sizeServiceWorker");
|
||||
className += " theme-comment";
|
||||
} else if (typeof transferredSize == "number") {
|
||||
text = getFormattedSize(transferredSize);
|
||||
} else if (transferredSize === null) {
|
||||
text = L10N.getStr("networkMenu.sizeUnavailable");
|
||||
}
|
||||
|
||||
return (
|
||||
div({
|
||||
className: "requests-list-subitem requests-list-transferred",
|
||||
title: text,
|
||||
},
|
||||
span({ className }, text),
|
||||
)
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
||||
const ContentSizeColumn = createFactory(createClass({
|
||||
displayName: "ContentSizeColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.contentSize !== nextProps.item.contentSize;
|
||||
},
|
||||
|
||||
render() {
|
||||
const { contentSize } = this.props.item;
|
||||
|
||||
let text;
|
||||
if (typeof contentSize == "number") {
|
||||
text = getFormattedSize(contentSize);
|
||||
}
|
||||
|
||||
return (
|
||||
div({
|
||||
className: "requests-list-subitem subitem-label requests-list-size",
|
||||
title: text,
|
||||
},
|
||||
span({ className: "subitem-label" }, text),
|
||||
)
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
||||
const UPDATED_WATERFALL_PROPS = [
|
||||
"eventTimings",
|
||||
"totalTime",
|
||||
"fromCache",
|
||||
"fromServiceWorker",
|
||||
];
|
||||
|
||||
const WaterfallColumn = createFactory(createClass({
|
||||
displayName: "WaterfallColumn",
|
||||
|
||||
propTypes: {
|
||||
firstRequestStartedMillis: PropTypes.number.isRequired,
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.firstRequestStartedMillis !== nextProps.firstRequestStartedMillis ||
|
||||
!propertiesEqual(UPDATED_WATERFALL_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
|
||||
render() {
|
||||
const { item, firstRequestStartedMillis } = this.props;
|
||||
|
||||
return (
|
||||
div({ className: "requests-list-subitem requests-list-waterfall" },
|
||||
div({
|
||||
className: "requests-list-timings",
|
||||
style: {
|
||||
paddingInlineStart: `${item.startedMillis - firstRequestStartedMillis}px`,
|
||||
},
|
||||
},
|
||||
timingBoxes(item),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
||||
// List of properties of the timing info we want to create boxes for
|
||||
const TIMING_KEYS = ["blocked", "dns", "connect", "send", "wait", "receive"];
|
||||
|
||||
function timingBoxes(item) {
|
||||
const { eventTimings, totalTime, fromCache, fromServiceWorker } = item;
|
||||
let boxes = [];
|
||||
|
||||
if (fromCache || fromServiceWorker) {
|
||||
return boxes;
|
||||
}
|
||||
|
||||
if (eventTimings) {
|
||||
// Add a set of boxes representing timing information.
|
||||
for (let key of TIMING_KEYS) {
|
||||
let width = eventTimings.timings[key];
|
||||
|
||||
// Don't render anything if it surely won't be visible.
|
||||
// One millisecond == one unscaled pixel.
|
||||
if (width > 0) {
|
||||
boxes.push(div({
|
||||
key,
|
||||
className: "requests-list-timings-box " + key,
|
||||
style: { width }
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof totalTime === "number") {
|
||||
let text = L10N.getFormatStr("networkMenu.totalMS", totalTime);
|
||||
boxes.push(div({
|
||||
key: "total",
|
||||
className: "requests-list-timings-total",
|
||||
title: text
|
||||
}, text));
|
||||
}
|
||||
|
||||
return boxes;
|
||||
}
|
||||
|
||||
module.exports = RequestListItem;
|
||||
|
@ -274,6 +274,13 @@ function ipToLong(ip) {
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two objects on a subset of their properties
|
||||
*/
|
||||
function propertiesEqual(props, item1, item2) {
|
||||
return item1 === item2 || props.every(p => item1[p] === item2[p]);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getFormDataSections,
|
||||
fetchHeaders,
|
||||
@ -289,5 +296,6 @@ module.exports = {
|
||||
getUrlDetails,
|
||||
parseQueryString,
|
||||
parseFormData,
|
||||
propertiesEqual,
|
||||
ipToLong,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user