author | Eduardo Boucas <mail@eduardoboucas.com> |
Fri, 03 Feb 2017 17:19:20 +0000 | |
changeset 340879 | 031087a1f3c654d9f3021401a945a61135124651 |
parent 340845 | be38817f54c5dc82b2dca9ede49cd7118f92d959 |
child 340880 | dee894afe7bbf05bc3599175dc7aff12493ec76a |
push id | 31318 |
push user | cbook@mozilla.com |
push date | Mon, 06 Feb 2017 11:56:59 +0000 |
treeherder | mozilla-central@1cc159c7a044 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | Honza |
bugs | 1320233 |
milestone | 54.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/devtools/client/locales/en-US/netmonitor.properties +++ b/devtools/client/locales/en-US/netmonitor.properties @@ -744,8 +744,12 @@ netmonitor.custom.send=Send # LOCALIZATION NOTE (netmonitor.custom.cancel): This is the label displayed # on the button which cancels and closes the custom request form netmonitor.custom.cancel=Cancel # LOCALIZATION NOTE (netmonitor.backButton): This is the label displayed # on the button which exists the performance statistics view netmonitor.backButton=Back + +# LOCALIZATION NOTE (netmonitor.headers.learnMore): This is the label displayed +# next to a header list item, with a link to external documentation +netmonitor.headers.learnMore=Learn More
new file mode 100644 --- /dev/null +++ b/devtools/client/netmonitor/shared/components/headers-mdn.js @@ -0,0 +1,119 @@ +/* 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/. */ + +/** + * A mapping of header names to external documentation. Any header included + * here will show a "Learn More" link alongside it. + */ + +"use strict"; + +var URL_DOMAIN = "https://developer.mozilla.org"; +const URL_PATH = "/en-US/docs/Web/HTTP/Headers/"; +const URL_PARAMS = + "?utm_source=mozilla&utm_medium=devtools-netmonitor&utm_campaign=default"; + +var SUPPORTED_HEADERS = [ + "Accept", + "Accept-Charset", + "Accept-Encoding", + "Accept-Language", + "Accept-Ranges", + "Access-Control-Allow-Credentials", + "Access-Control-Allow-Headers", + "Access-Control-Allow-Methods", + "Access-Control-Allow-Origin", + "Access-Control-Expose-Headers", + "Access-Control-Max-Age", + "Access-Control-Request-Headers", + "Access-Control-Request-Method", + "Age", + "Cache-Control", + "Connection", + "Content-Disposition", + "Content-Encoding", + "Content-Language", + "Content-Length", + "Content-Location", + "Content-Security-Policy", + "Content-Security-Policy-Report-Only", + "Content-Type", + "Cookie", + "Cookie2", + "DNT", + "Date", + "ETag", + "Expires", + "From", + "Host", + "If-Match", + "If-Modified-Since", + "If-None-Match", + "If-Range", + "If-Unmodified-Since", + "Keep-Alive", + "Last-Modified", + "Location", + "Origin", + "Pragma", + "Public-Key-Pins", + "Public-Key-Pins-Report-Only", + "Referer", + "Referrer-Policy", + "Retry-After", + "Server", + "Set-Cookie", + "Set-Cookie2", + "Strict-Transport-Security", + "TE", + "Tk", + "Trailer", + "Transfer-Encoding", + "Upgrade-Insecure-Requests", + "User-Agent", + "Vary", + "Via", + "Warning", + "X-Content-Type-Options", + "X-DNS-Prefetch-Control", + "X-Frame-Options", + "X-XSS-Protection" +]; + +/** + * Get the MDN URL for the specified header + * + * @param {string} Name of the header + * The baseURL to use. + * + * @return {string} + * The MDN URL for the header, or null if not available. + */ +exports.getURL = (header) => { + if (SUPPORTED_HEADERS.indexOf(header) === -1) { + return null; + } + + return URL_DOMAIN + URL_PATH + header + URL_PARAMS; +}; + +/** + * Use a different domain for the URLs. Used only for testing. + * + * @param {string} domain + * The domain to use. + */ +exports.setDomain = (domain) => { + URL_DOMAIN = domain; +}; + +/** + * Use a different list of supported headers. Used only for testing. + * + * @param {array} headers + * The supported headers to use. + */ +exports.setSupportedHeaders = (headers) => { + SUPPORTED_HEADERS = headers; +};
--- a/devtools/client/netmonitor/shared/components/headers-panel.js +++ b/devtools/client/netmonitor/shared/components/headers-panel.js @@ -10,21 +10,26 @@ const { createClass, createFactory, DOM, PropTypes, } = require("devtools/client/shared/vendor/react"); const { L10N } = require("../../l10n"); const { writeHeaderText } = require("../../request-utils"); const { getFormattedSize } = require("../../utils/format-utils"); +const Services = require("Services"); +const { gDevTools } = require("devtools/client/framework/devtools"); +const HeadersMDN = require("devtools/client/netmonitor/shared/components/headers-mdn"); +const { REPS, MODE } = require("devtools/client/shared/components/reps/load-reps"); +const Rep = createFactory(REPS.Rep); // Components const PropertiesView = createFactory(require("./properties-view")); -const { div, input, textarea } = DOM; +const { a, div, input, textarea } = DOM; const EDIT_AND_RESEND = L10N.getStr("netmonitor.summary.editAndResend"); const RAW_HEADERS = L10N.getStr("netmonitor.summary.rawHeaders"); const RAW_HEADERS_REQUEST = L10N.getStr("netmonitor.summary.rawHeaders.requestHeaders"); const RAW_HEADERS_RESPONSE = L10N.getStr("netmonitor.summary.rawHeaders.responseHeaders"); const HEADERS_EMPTY_TEXT = L10N.getStr("headersEmptyText"); const HEADERS_FILTER_TEXT = L10N.getStr("headersFilterText"); const REQUEST_HEADERS = L10N.getStr("requestHeaders"); const REQUEST_HEADERS_FROM_UPLOAD = L10N.getStr("requestHeadersFromUpload"); @@ -40,16 +45,17 @@ const SUMMARY_VERSION = L10N.getStr("net * Lists basic information about the request */ const HeadersPanel = createClass({ displayName: "HeadersPanel", propTypes: { cloneSelectedRequest: PropTypes.func.isRequired, request: PropTypes.object.isRequired, + renderValue: PropTypes.func }, getInitialState() { return { rawHeadersOpened: false, }; }, @@ -208,15 +214,54 @@ const HeadersPanel = createClass({ summaryStatus, summaryVersion, summaryRawHeaders, ), PropertiesView({ object, filterPlaceHolder: HEADERS_FILTER_TEXT, sectionNames: Object.keys(object), + renderValue }), ) ); } }); +function onLearnMoreClick(e, headerDocURL) { + e.stopPropagation(); + e.preventDefault(); + + let win = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType); + win.openUILinkIn(headerDocURL, "tab"); +} + +function renderValue(props) { + const { member, value } = props; + + if (typeof value !== "string") { + return null; + } + + let headerDocURL = HeadersMDN.getURL(member.name); + + return ( + div({ className: "treeValueCellDivider" }, + Rep(Object.assign(props, { + // FIXME: A workaround for the issue in StringRep + // Force StringRep to crop the text everytime + member: Object.assign({}, member, { open: false }), + mode: MODE.TINY, + cropLimit: 60, + })), + headerDocURL ? + a({ + className: "learn-more-link", + title: headerDocURL, + onClick: (e) => onLearnMoreClick(e, headerDocURL), + }, `[${L10N.getStr("netmonitor.headers.learnMore")}]`) + : + null + ) + ); +} + module.exports = HeadersPanel;
--- a/devtools/client/netmonitor/shared/components/moz.build +++ b/devtools/client/netmonitor/shared/components/moz.build @@ -1,16 +1,17 @@ # 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/. DevToolsModules( 'cookies-panel.js', 'details-panel.js', 'editor.js', + 'headers-mdn.js', 'headers-panel.js', 'params-panel.js', 'preview-panel.js', 'properties-view.js', 'response-panel.js', 'security-panel.js', 'timings-panel.js', )
--- a/devtools/client/netmonitor/test/browser.ini +++ b/devtools/client/netmonitor/test/browser.ini @@ -93,16 +93,17 @@ subsuite = clipboard skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts [browser_net_copy_as_curl.js] subsuite = clipboard skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts [browser_net_cors_requests.js] [browser_net_cyrillic-01.js] [browser_net_cyrillic-02.js] [browser_net_frame.js] +[browser_net_header-docs.js] skip-if = (os == 'linux' && debug && bits == 32) # Bug 1321434 [browser_net_filter-01.js] skip-if = (os == 'linux' && debug && bits == 32) # Bug 1303439 [browser_net_filter-02.js] [browser_net_filter-03.js] [browser_net_filter-04.js] [browser_net_footer-summary.js] [browser_net_html-preview.js]
new file mode 100644 --- /dev/null +++ b/devtools/client/netmonitor/test/browser_net_header-docs.js @@ -0,0 +1,56 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const HeadersMDN = require("devtools/client/netmonitor/shared/components/headers-mdn"); + +/** + * Tests if "Learn More" links are correctly displayed + * next to headers. + */ +add_task(function* () { + let { tab, monitor } = yield initNetMonitor(POST_DATA_URL); + info("Starting test... "); + + let { document, NetMonitorView } = monitor.panelWin; + let { RequestsMenu } = NetMonitorView; + + RequestsMenu.lazyUpdate = false; + + let wait = waitForNetworkEvents(monitor, 0, 2); + yield ContentTask.spawn(tab.linkedBrowser, {}, function* () { + content.wrappedJSObject.performRequests(); + }); + yield wait; + + let origItem = RequestsMenu.getItemAtIndex(0); + RequestsMenu.selectedItem = origItem; + + EventUtils.sendMouseEvent({ type: "click" }, + document.querySelectorAll(".request-list-item")[0]); + + testShowLearnMore(origItem); + + return teardown(monitor); + + /* + * Tests that a "Learn More" button is only shown if + * and only if a header is documented in MDN. + */ + function testShowLearnMore(data) { + document.querySelectorAll(".properties-view .treeRow.stringRow").forEach((rowEl, index) => { + let headerName = rowEl.querySelectorAll(".treeLabelCell .treeLabel")[0].textContent; + let headerDocURL = HeadersMDN.getURL(headerName); + let learnMoreEl = rowEl.querySelectorAll(".treeValueCell .learn-more-link"); + + if (headerDocURL === null) { + ok(learnMoreEl.length === 0, + "undocumented header does not include a \"Learn More\" button"); + } else { + ok(learnMoreEl[0].getAttribute("title") === headerDocURL, + "documented header includes a \"Learn More\" button with a link to MDN"); + } + }); + } +});
--- a/devtools/client/shared/components/tree/tree-view.css +++ b/devtools/client/shared/components/tree/tree-view.css @@ -72,16 +72,33 @@ text-decoration: underline; } /* Filtering */ .treeTable .treeRow.hidden { display: none; } +.treeTable .treeValueCellDivider { + display: flex; + flex-wrap: wrap; + justify-content: space-between; +} + +/* Learn More link */ +.treeTable .treeValueCell .learn-more-link { + color: var(--theme-highlight-blue); + cursor: pointer; + margin: 0 5px; +} + +.treeTable .treeValueCell .learn-more-link:hover { + text-decoration: underline; +} + /******************************************************************************/ /* Toggle Icon */ .treeTable .treeRow .treeIcon { height: 14px; width: 14px; font-size: 10px; /* Set the size of loading spinner */ display: inline-block;