summaryrefslogtreecommitdiffstats
path: root/devtools/client/netmonitor/src/components/request-details/CookiesPanel.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--devtools/client/netmonitor/src/components/request-details/CookiesPanel.js225
1 files changed, 225 insertions, 0 deletions
diff --git a/devtools/client/netmonitor/src/components/request-details/CookiesPanel.js b/devtools/client/netmonitor/src/components/request-details/CookiesPanel.js
new file mode 100644
index 0000000000..466c0379cd
--- /dev/null
+++ b/devtools/client/netmonitor/src/components/request-details/CookiesPanel.js
@@ -0,0 +1,225 @@
+/* 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 {
+ Component,
+ createFactory,
+} = 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 {
+ L10N,
+} = require("resource://devtools/client/netmonitor/src/utils/l10n.js");
+const {
+ fetchNetworkUpdatePacket,
+} = require("resource://devtools/client/netmonitor/src/utils/request-utils.js");
+const {
+ sortObjectKeys,
+} = require("resource://devtools/client/netmonitor/src/utils/sort-utils.js");
+const {
+ FILTER_SEARCH_DELAY,
+} = require("resource://devtools/client/netmonitor/src/constants.js");
+
+// Component
+const PropertiesView = createFactory(
+ require("resource://devtools/client/netmonitor/src/components/request-details/PropertiesView.js")
+);
+const SearchBox = createFactory(
+ require("resource://devtools/client/shared/components/SearchBox.js")
+);
+const Accordion = createFactory(
+ require("resource://devtools/client/shared/components/Accordion.js")
+);
+
+loader.lazyGetter(this, "TreeRow", function () {
+ return createFactory(
+ require("resource://devtools/client/shared/components/tree/TreeRow.js")
+ );
+});
+
+const { div } = dom;
+
+const COOKIES_EMPTY_TEXT = L10N.getStr("cookiesEmptyText");
+const COOKIES_FILTER_TEXT = L10N.getStr("cookiesFilterText");
+const REQUEST_COOKIES = L10N.getStr("requestCookies");
+const RESPONSE_COOKIES = L10N.getStr("responseCookies");
+
+/*
+ * Cookies panel component
+ * This tab lists full details of any cookies sent with the request or response
+ */
+class CookiesPanel extends Component {
+ static get propTypes() {
+ return {
+ connector: PropTypes.object.isRequired,
+ openLink: PropTypes.func,
+ request: PropTypes.object.isRequired,
+ targetSearchResult: PropTypes.object,
+ };
+ }
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ filterText: "",
+ };
+ }
+
+ componentDidMount() {
+ const { connector, request } = this.props;
+ fetchNetworkUpdatePacket(connector.requestData, request, [
+ "requestCookies",
+ "responseCookies",
+ ]);
+ }
+
+ // FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=1774507
+ UNSAFE_componentWillReceiveProps(nextProps) {
+ const { connector, request } = nextProps;
+ fetchNetworkUpdatePacket(connector.requestData, request, [
+ "requestCookies",
+ "responseCookies",
+ ]);
+ }
+
+ /**
+ * Mapping array to dict for TreeView usage.
+ * Since TreeView only support Object(dict) format.
+ *
+ * @param {Object[]} arr - key-value pair array like cookies or params
+ * @returns {Object}
+ */
+ getProperties(arr, title) {
+ const cookies = arr.reduce((map, obj) => {
+ // Generally cookies object contains only name and value properties and can
+ // be rendered as name: value pair.
+ // When there are more properties in cookies object such as extra or path,
+ // We will pass the object to display these extra information
+ if (Object.keys(obj).length > 2) {
+ map[obj.name] = Object.assign({}, obj);
+ delete map[obj.name].name;
+ } else {
+ map[obj.name] = obj.value;
+ }
+ return map;
+ }, Object.create(null));
+
+ // To have different roots for Request and Response cookies
+ return { [title]: cookies };
+ }
+
+ /**
+ * Custom rendering method passed to PropertiesView. It's
+ * responsible to filter out level 0 node in the tree
+ *
+ * @param {Object} props
+ */
+ renderRow(props) {
+ const { level } = props.member;
+
+ if (level === 0) {
+ return null;
+ }
+
+ return TreeRow(props);
+ }
+
+ /**
+ * Get the selected cookies path
+ * @param {Object} searchResult
+ * @returns {string}
+ */
+ getTargetCookiePath(searchResult) {
+ if (!searchResult) {
+ return null;
+ }
+
+ switch (searchResult.type) {
+ case "requestCookies": {
+ return `/${REQUEST_COOKIES}/${searchResult.label}`;
+ }
+ case "responseCookies":
+ return `/${RESPONSE_COOKIES}/${searchResult.label}`;
+ }
+
+ return null;
+ }
+
+ render() {
+ let {
+ request: {
+ requestCookies = { cookies: [] },
+ responseCookies = { cookies: [] },
+ },
+ targetSearchResult,
+ } = this.props;
+
+ const { filterText } = this.state;
+
+ requestCookies = requestCookies.cookies || requestCookies;
+ responseCookies = responseCookies.cookies || responseCookies;
+
+ if (!requestCookies.length && !responseCookies.length) {
+ return div({ className: "empty-notice" }, COOKIES_EMPTY_TEXT);
+ }
+
+ const items = [];
+
+ if (responseCookies.length) {
+ items.push({
+ component: PropertiesView,
+ componentProps: {
+ object: sortObjectKeys(
+ this.getProperties(responseCookies, RESPONSE_COOKIES)
+ ),
+ filterText,
+ targetSearchResult,
+ defaultSelectFirstNode: false,
+ selectPath: this.getTargetCookiePath,
+ renderRow: this.renderRow,
+ },
+ header: RESPONSE_COOKIES,
+ id: "responseCookies",
+ opened: true,
+ });
+ }
+
+ if (requestCookies.length) {
+ items.push({
+ component: PropertiesView,
+ componentProps: {
+ object: sortObjectKeys(
+ this.getProperties(requestCookies, REQUEST_COOKIES)
+ ),
+ filterText,
+ targetSearchResult,
+ defaultSelectFirstNode: false,
+ selectPath: this.getTargetCookiePath,
+ renderRow: this.renderRow,
+ },
+ header: REQUEST_COOKIES,
+ id: "requestCookies",
+ opened: true,
+ });
+ }
+
+ return div(
+ { className: "panel-container cookies-panel-container" },
+ div(
+ { className: "devtools-toolbar devtools-input-toolbar" },
+ SearchBox({
+ delay: FILTER_SEARCH_DELAY,
+ type: "filter",
+ onChange: text => this.setState({ filterText: text }),
+ placeholder: COOKIES_FILTER_TEXT,
+ })
+ ),
+ Accordion({ items })
+ );
+ }
+}
+
+module.exports = CookiesPanel;