diff options
Diffstat (limited to 'devtools/client/webconsole/components/Output/message-types/NetworkEventMessage.js')
-rw-r--r-- | devtools/client/webconsole/components/Output/message-types/NetworkEventMessage.js | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/devtools/client/webconsole/components/Output/message-types/NetworkEventMessage.js b/devtools/client/webconsole/components/Output/message-types/NetworkEventMessage.js new file mode 100644 index 0000000000..ce0961668b --- /dev/null +++ b/devtools/client/webconsole/components/Output/message-types/NetworkEventMessage.js @@ -0,0 +1,243 @@ +/* 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"; + +// React & Redux +const { + createFactory, + createElement, +} = require("resource://devtools/client/shared/vendor/react.js"); +const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js"); +const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); +const Message = createFactory( + require("resource://devtools/client/webconsole/components/Output/Message.js") +); +const actions = require("resource://devtools/client/webconsole/actions/index.js"); +const { + isMessageNetworkError, + l10n, +} = require("resource://devtools/client/webconsole/utils/messages.js"); + +loader.lazyRequireGetter( + this, + "TabboxPanel", + "resource://devtools/client/netmonitor/src/components/TabboxPanel.js" +); +const { + getHTTPStatusCodeURL, +} = require("resource://devtools/client/netmonitor/src/utils/doc-utils.js"); +const { + getUnicodeUrl, +} = require("resource://devtools/client/shared/unicode-url.js"); +loader.lazyRequireGetter( + this, + "BLOCKED_REASON_MESSAGES", + "resource://devtools/client/netmonitor/src/constants.js", + true +); + +const LEARN_MORE = l10n.getStr("webConsoleMoreInfoLabel"); + +const isMacOS = Services.appinfo.OS === "Darwin"; + +NetworkEventMessage.displayName = "NetworkEventMessage"; + +NetworkEventMessage.propTypes = { + message: PropTypes.object.isRequired, + serviceContainer: PropTypes.shape({ + openNetworkPanel: PropTypes.func.isRequired, + resendNetworkRequest: PropTypes.func.isRequired, + }), + timestampsVisible: PropTypes.bool.isRequired, + networkMessageUpdate: PropTypes.object.isRequired, +}; + +/** + * This component is responsible for rendering network messages + * in the Console panel. + * + * Network logs are expandable and the user can inspect it inline + * within the Console panel (no need to switch to the Network panel). + * + * HTTP details are rendered using `TabboxPanel` component used to + * render contents of the side bar in the Network panel. + * + * All HTTP details data are fetched from the backend on-demand + * when the user is expanding network log for the first time. + */ +function NetworkEventMessage({ + message = {}, + serviceContainer, + timestampsVisible, + networkMessageUpdate = {}, + networkMessageActiveTabId, + dispatch, + open, + disabled, +}) { + const { + id, + indent, + source, + type, + level, + url, + method, + isXHR, + timeStamp, + blockedReason, + httpVersion, + status, + statusText, + totalTime, + } = message; + + const topLevelClasses = ["cm-s-mozilla"]; + if (isMessageNetworkError(message)) { + topLevelClasses.push("error"); + } + + let statusCode, statusInfo; + + if ( + httpVersion && + status && + statusText !== undefined && + totalTime !== undefined + ) { + const statusCodeDocURL = getHTTPStatusCodeURL( + status.toString(), + "webconsole" + ); + statusCode = dom.span( + { + className: "status-code", + "data-code": status, + title: LEARN_MORE, + onClick: e => { + e.stopPropagation(); + e.preventDefault(); + serviceContainer.openLink(statusCodeDocURL, e); + }, + }, + status + ); + statusInfo = dom.span( + { className: "status-info" }, + `[${httpVersion} `, + statusCode, + ` ${statusText} ${totalTime}ms]` + ); + } + + if (blockedReason) { + statusInfo = dom.span( + { className: "status-info" }, + BLOCKED_REASON_MESSAGES[blockedReason] + ); + topLevelClasses.push("network-message-blocked"); + } + + // Message body components. + const requestMethod = dom.span({ className: "method" }, method); + const xhr = isXHR + ? dom.span({ className: "xhr" }, l10n.getStr("webConsoleXhrIndicator")) + : null; + const unicodeURL = getUnicodeUrl(url); + const requestUrl = dom.a( + { + className: "url", + title: unicodeURL, + href: url, + onClick: e => { + // The href of the <a> is the actual URL, so we need to prevent the navigation + // within the console panel. + // We only want to handle Ctrl/Cmd + click to open the link in a new tab. + e.preventDefault(); + const shouldOpenLink = + (isMacOS && e.metaKey) || (!isMacOS && e.ctrlKey); + if (shouldOpenLink) { + e.stopPropagation(); + serviceContainer.openLink(url, e); + } + }, + }, + unicodeURL + ); + const statusBody = statusInfo + ? dom.a({ className: "status" }, statusInfo) + : null; + + const messageBody = [xhr, requestMethod, requestUrl, statusBody]; + + // API consumed by Net monitor UI components. Most of the method + // are not needed in context of the Console panel (atm) and thus + // let's just provide empty implementation. + // Individual methods might be implemented step by step as needed. + const connector = { + viewSourceInDebugger: (srcUrl, line, column) => { + serviceContainer.onViewSourceInDebugger({ url: srcUrl, line, column }); + }, + getLongString: grip => { + return serviceContainer.getLongString(grip); + }, + triggerActivity: () => {}, + requestData: (requestId, dataType) => { + return serviceContainer.requestData(requestId, dataType); + }, + }; + + // Only render the attachment if the network-event is + // actually opened (performance optimization) and its not disabled. + const attachment = + open && + !disabled && + dom.div( + { + className: "network-info network-monitor", + }, + createElement(TabboxPanel, { + connector, + activeTabId: networkMessageActiveTabId, + request: networkMessageUpdate, + sourceMapURLService: serviceContainer.sourceMapURLService, + openLink: serviceContainer.openLink, + selectTab: tabId => { + dispatch(actions.selectNetworkMessageTab(tabId)); + }, + openNetworkDetails: enabled => { + if (!enabled) { + dispatch(actions.messageClose(id)); + } + }, + hideToggleButton: true, + showMessagesView: false, + }) + ); + + const request = { url, method }; + return Message({ + dispatch, + messageId: id, + source, + type, + level, + indent, + collapsible: true, + open, + disabled, + attachment, + topLevelClasses, + timeStamp, + messageBody, + serviceContainer, + request, + timestampsVisible, + isBlockedNetworkMessage: !!blockedReason, + message, + }); +} + +module.exports = NetworkEventMessage; |