Bug 1353319 - Render HTML preview within Response side-panel. r=Honza

Restoring the HTML preview in the response panel was requested by many
users who rely on it to debug erroring AJAX requests. Many web backend
frameworks display an HTML stacktrace helping users trace down the
problem.

The html-preview.js component was taken from a previous commit of the
source code before the preview panel was removed. A few modifications
with its name and CSS classname were made.

MozReview-Commit-ID: JFyF6cBMaNf

--HG--
extra : rebase_source : 7e358f5fb4336a15f549ecb6f7e24cc00429de8e
This commit is contained in:
Brandon Cheng 2017-10-28 23:33:02 -04:00
Родитель f58e9c058c
Коммит af6599148d
6 изменённых файлов: 93 добавлений и 6 удалений

Просмотреть файл

@ -135,6 +135,10 @@ jsonScopeName=JSON
# in the response tab of the network details pane for a JSONP scope.
jsonpScopeName=JSONP → callback %S()
# LOCALIZATION NOTE (responsePreview): This is the text displayed
# in the response tab of the network details pane for an HTML preview.
responsePreview=Preview
# LOCALIZATION NOTE (networkMenu.sortedAsc): This is the tooltip displayed
# in the network table toolbar, for any column that is sorted ascending.
networkMenu.sortedAsc=Sorted ascending

Просмотреть файл

@ -255,6 +255,27 @@
max-height: 100px;
}
.network-monitor .tree-container .treeTable tr.response-preview-container {
flex: 1;
min-height: 0;
}
.network-monitor .tree-container .treeTable tr.response-preview-container td {
display: block;
height: 100%;
}
.network-monitor .html-preview {
height: 100%;
}
.network-monitor .html-preview iframe {
background-color: #fff;
border: none;
height: 100%;
width: 100%;
}
/* Timings tabpanel */
.network-monitor .timings-container {

Просмотреть файл

@ -0,0 +1,33 @@
/* 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 { DOM, PropTypes } = require("devtools/client/shared/vendor/react");
const { div, iframe } = DOM;
/*
* Response preview component
* Display HTML content within a sandbox enabled iframe
*/
function HTMLPreview({ responseContent }) {
const htmlBody = responseContent ? responseContent.content.text : "";
return (
div({ className: "html-preview" },
iframe({
sandbox: "",
srcDoc: typeof htmlBody === "string" ? htmlBody : "",
})
)
);
}
HTMLPreview.displayName = "HTMLPreview";
HTMLPreview.propTypes = {
requestContent: PropTypes.object.isRequired,
};
module.exports = HTMLPreview;

Просмотреть файл

@ -24,11 +24,13 @@ const TreeViewClass = require("devtools/client/shared/components/tree/TreeView")
const TreeView = createFactory(TreeViewClass);
const TreeRow = createFactory(require("devtools/client/shared/components/tree/TreeRow"));
const SourceEditor = createFactory(require("./SourceEditor"));
const HTMLPreview = createFactory(require("./HtmlPreview"));
const { div, tr, td } = DOM;
const AUTO_EXPAND_MAX_LEVEL = 7;
const AUTO_EXPAND_MAX_NODES = 50;
const EDITOR_CONFIG_ID = "EDITOR_CONFIG";
const HTML_PREVIEW_ID = "HTML_PREVIEW";
/*
* Properties View component
@ -38,6 +40,7 @@ const EDITOR_CONFIG_ID = "EDITOR_CONFIG";
* Search filter - Set enableFilter to enable / disable SearchBox feature.
* Tree view - Default enabled.
* Source editor - Enable by specifying object level 1 property name to EDITOR_CONFIG_ID.
* HTML preview - Enable by specifying object level 1 property name to HTML_PREVIEW_ID.
* Rep - Default enabled.
*/
class PropertiesView extends Component {
@ -73,7 +76,7 @@ class PropertiesView extends Component {
this.getRowClass = this.getRowClass.bind(this);
this.onFilter = this.onFilter.bind(this);
this.renderRowWithEditor = this.renderRowWithEditor.bind(this);
this.renderRowWithExtras = this.renderRowWithExtras.bind(this);
this.renderValueWithRep = this.renderValueWithRep.bind(this);
this.shouldRenderSearchBox = this.shouldRenderSearchBox.bind(this);
this.updateFilterText = this.updateFilterText.bind(this);
@ -95,7 +98,7 @@ class PropertiesView extends Component {
return jsonString.includes(filterText.toLowerCase());
}
renderRowWithEditor(props) {
renderRowWithExtras(props) {
const { level, name, value, path } = props.member;
// Display source editor when specifying to EDITOR_CONFIG_ID along with config
@ -109,8 +112,20 @@ class PropertiesView extends Component {
);
}
// Skip for editor config
if (level >= 1 && path.includes(EDITOR_CONFIG_ID)) {
// Similar to the source editor, display a preview when specifying HTML_PREVIEW_ID
if (level === 1 && name === HTML_PREVIEW_ID) {
return (
tr({ key: HTML_PREVIEW_ID, className: "response-preview-container" },
td({ colSpan: 2 },
HTMLPreview(value)
)
)
);
}
// Skip for editor config and HTML previews
if ((path.includes(EDITOR_CONFIG_ID) || path.includes(HTML_PREVIEW_ID))
&& level >= 1) {
return null;
}
@ -139,9 +154,13 @@ class PropertiesView extends Component {
}));
}
sectionIsSearchable(object, section) {
return !(object[section][EDITOR_CONFIG_ID] || object[section][HTML_PREVIEW_ID]);
}
shouldRenderSearchBox(object) {
return this.props.enableFilter && object && Object.keys(object)
.filter((section) => !object[section][EDITOR_CONFIG_ID]).length > 0;
.filter((section) => this.sectionIsSearchable(object, section)).length > 0;
}
updateFilterText(filterText) {
@ -192,7 +211,7 @@ class PropertiesView extends Component {
{maxLevel: AUTO_EXPAND_MAX_LEVEL, maxNodes: AUTO_EXPAND_MAX_NODES}
),
onFilter: (props) => this.onFilter(props, sectionNames),
renderRow: renderRow || this.renderRowWithEditor,
renderRow: renderRow || this.renderRowWithExtras,
renderValue: renderValue || this.renderValueWithRep,
openLink,
}),

Просмотреть файл

@ -16,6 +16,7 @@ const {
formDataURI,
getUrlBaseName,
} = require("../utils/request-utils");
const { Filters } = require("../utils/filter-predicates");
// Components
const PropertiesView = createFactory(require("./PropertiesView"));
@ -27,6 +28,7 @@ const RESPONSE_IMG_NAME = L10N.getStr("netmonitor.response.name");
const RESPONSE_IMG_DIMENSIONS = L10N.getStr("netmonitor.response.dimensions");
const RESPONSE_IMG_MIMETYPE = L10N.getStr("netmonitor.response.mime");
const RESPONSE_PAYLOAD = L10N.getStr("responsePayload");
const RESPONSE_PREVIEW = L10N.getStr("responsePreview");
const JSON_VIEW_MIME_TYPE = "application/vnd.mozilla.json.view";
@ -176,6 +178,13 @@ class ResponsePanel extends Component {
object[sectionName] = json;
}
// Display HTML under Properties View
if (Filters.html(this.props.request)) {
object[RESPONSE_PREVIEW] = {
HTML_PREVIEW: { responseContent }
};
}
// Others like text/html, text/plain, application/javascript
object[RESPONSE_PAYLOAD] = {
EDITOR_CONFIG: {

Просмотреть файл

@ -7,6 +7,7 @@ DevToolsModules(
'CookiesPanel.js',
'CustomRequestPanel.js',
'HeadersPanel.js',
'HtmlPreview.js',
'MdnLink.js',
'MonitorPanel.js',
'NetworkDetailsPanel.js',