Bug 1294498 - New console frontend: Add a file location component. r=linclark
authorJaideep Bhoosreddy <jaideep.coder@gmail.com>
Thu, 18 Aug 2016 16:04:33 -0700
changeset 309891 bb03d58f1435fbfadde5c0a069131223d0ea696c
parent 309890 e7ab4bc97bd0ead33c58a5a08427de48df29eea1
child 309892 e88f6f84ce032a9a6bb2de6df763b957aafccdf2
push id20341
push userbgrinstead@mozilla.com
push dateThu, 18 Aug 2016 23:06:20 +0000
treeherderfx-team@7bf7d0d47b79 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslinclark
bugs1294498
milestone51.0a1
Bug 1294498 - New console frontend: Add a file location component. r=linclark MozReview-Commit-ID: 5VnQnWQsoZF
devtools/client/webconsole/new-console-output/components/console-output.js
devtools/client/webconsole/new-console-output/components/message-container.js
devtools/client/webconsole/new-console-output/components/message-types/console-api-call.js
devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
devtools/client/webconsole/new-console-output/test/fixtures/stubs.js
devtools/client/webconsole/new-console-output/types.js
devtools/client/webconsole/new-console-output/utils/messages.js
--- a/devtools/client/webconsole/new-console-output/components/console-output.js
+++ b/devtools/client/webconsole/new-console-output/components/console-output.js
@@ -15,16 +15,17 @@ const { connect } = require("devtools/cl
 const { getAllMessages } = require("devtools/client/webconsole/new-console-output/selectors/messages");
 const MessageContainer = createFactory(require("devtools/client/webconsole/new-console-output/components/message-container").MessageContainer);
 
 const ConsoleOutput = createClass({
 
   propTypes: {
     jsterm: PropTypes.object.isRequired,
     messages: PropTypes.object.isRequired,
+    sourceMapService: PropTypes.object,
     onViewSourceInDebugger: PropTypes.func.isRequired,
   },
 
   displayName: "ConsoleOutput",
 
   componentWillUpdate() {
     let node = ReactDOM.findDOMNode(this);
     if (node.lastChild) {
@@ -35,20 +36,21 @@ const ConsoleOutput = createClass({
   componentDidUpdate() {
     if (this.shouldScrollBottom) {
       let node = ReactDOM.findDOMNode(this);
       node.scrollTop = node.scrollHeight;
     }
   },
 
   render() {
-    let {messages, onViewSourceInDebugger} = this.props;
+    let {messages, sourceMapService, onViewSourceInDebugger} = this.props;
     let messageNodes = messages.map(function (message) {
       return (
-        MessageContainer({ message, key: message.id, onViewSourceInDebugger })
+        MessageContainer({ message, key: message.id,
+          sourceMapService, onViewSourceInDebugger })
       );
     });
     return (
       dom.div({className: "webconsole-output"}, messageNodes)
     );
   }
 });
 
--- a/devtools/client/webconsole/new-console-output/components/message-container.js
+++ b/devtools/client/webconsole/new-console-output/components/message-container.js
@@ -26,27 +26,28 @@ const componentMap = new Map([
   ["PageError", require("./message-types/page-error").PageError]
 ]);
 
 const MessageContainer = createClass({
   displayName: "MessageContainer",
 
   propTypes: {
     message: PropTypes.object.isRequired,
+    sourceMapService: PropTypes.object,
     onViewSourceInDebugger: PropTypes.func.isRequired,
   },
 
   shouldComponentUpdate(nextProps, nextState) {
     return this.props.message.repeat !== nextProps.message.repeat;
   },
 
   render() {
-    const { message, onViewSourceInDebugger } = this.props;
+    const { message, sourceMapService, onViewSourceInDebugger } = this.props;
     let MessageComponent = createFactory(getMessageComponent(message));
-    return MessageComponent({ message, onViewSourceInDebugger });
+    return MessageComponent({ message, sourceMapService, onViewSourceInDebugger });
   }
 });
 
 function getMessageComponent(message) {
   switch (message.source) {
     case MESSAGE_SOURCE.CONSOLE_API:
       return componentMap.get("ConsoleApiCall");
     case MESSAGE_SOURCE.JAVASCRIPT:
--- a/devtools/client/webconsole/new-console-output/components/message-types/console-api-call.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/console-api-call.js
@@ -7,32 +7,33 @@
 "use strict";
 
 // React & Redux
 const {
   createFactory,
   DOM: dom,
   PropTypes
 } = require("devtools/client/shared/vendor/react");
+const FrameView = createFactory(require("devtools/client/shared/components/frame"));
 const StackTrace = createFactory(require("devtools/client/shared/components/stack-trace"));
 const GripMessageBody = createFactory(require("devtools/client/webconsole/new-console-output/components/grip-message-body").GripMessageBody);
 const MessageRepeat = createFactory(require("devtools/client/webconsole/new-console-output/components/message-repeat").MessageRepeat);
 const MessageIcon = createFactory(require("devtools/client/webconsole/new-console-output/components/message-icon").MessageIcon);
 
 ConsoleApiCall.displayName = "ConsoleApiCall";
 
 ConsoleApiCall.propTypes = {
   message: PropTypes.object.isRequired,
+  sourceMapService: PropTypes.object,
   onViewSourceInDebugger: PropTypes.func.isRequired,
 };
 
 function ConsoleApiCall(props) {
-  const { message, onViewSourceInDebugger } = props;
-  const {source, level, stacktrace, type} = message;
-
+  const { message, sourceMapService, onViewSourceInDebugger } = props;
+  const { source, level, stacktrace, type, frame } = message;
   let messageBody;
   if (type === "trace") {
     messageBody = dom.span({className: "cm-variable"}, "console.trace()");
   } else if (message.parameters) {
     messageBody = message.parameters.map((grip, key) => GripMessageBody({grip, key}));
   } else {
     messageBody = message.messageText;
   }
@@ -59,29 +60,38 @@ function ConsoleApiCall(props) {
   if (level) {
     classes.push(level);
   }
 
   if (type === "trace") {
     classes.push("open");
   }
 
+  const shouldRenderFrame = frame && frame.source !== "debugger eval code";
   return dom.div({
     className: classes.join(" ")
   },
     // @TODO add timestamp
     // @TODO add indent if necessary
     icon,
     dom.span({className: "message-body-wrapper"},
       dom.span({},
         dom.span({className: "message-flex-body"},
           dom.span({className: "message-body devtools-monospace"},
             messageBody
           ),
-          repeat
+          repeat,
+          dom.span({ className: "message-location devtools-monospace" },
+            shouldRenderFrame ? FrameView({
+              frame,
+              onClick: onViewSourceInDebugger,
+              showEmptyPathAsHost: true,
+              sourceMapService
+            }) : null
+          )
         ),
         attachment
       )
     )
   );
 }
 
 module.exports.ConsoleApiCall = ConsoleApiCall;
--- a/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
+++ b/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
@@ -12,18 +12,20 @@ const actions = require("devtools/client
 const { configureStore } = require("devtools/client/webconsole/new-console-output/store");
 
 const ConsoleOutput = React.createFactory(require("devtools/client/webconsole/new-console-output/components/console-output"));
 const FilterBar = React.createFactory(require("devtools/client/webconsole/new-console-output/components/filter-bar"));
 
 const store = configureStore();
 
 function NewConsoleOutputWrapper(parentNode, jsterm, toolbox) {
+  const sourceMapService = toolbox ? toolbox._sourceMapService : null;
   let childComponent = ConsoleOutput({
     jsterm,
+    sourceMapService,
     onViewSourceInDebugger: frame => toolbox.viewSourceInDebugger.call(
       toolbox,
       frame.url,
       frame.line
     )
   });
   let filterBar = FilterBar({});
   let provider = React.createElement(
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stubs.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs.js
@@ -18,17 +18,22 @@ exports.stubConsoleMessages = new Map([
       allowRepeating: true,
       source: MESSAGE_SOURCE.CONSOLE_API,
       type: MESSAGE_TYPE.LOG,
       level: MESSAGE_LEVEL.LOG,
       messageText: null,
       parameters: ["foobar", "test"],
       repeat: 1,
       repeatId: null,
-      stacktrace: undefined
+      stacktrace: undefined,
+      frame: {
+        source: "file:///test.html",
+        line: 1,
+        column: 1
+      }
     })
   ],
   [
     "console.warn('danger, will robinson!')",
     new ConsoleMessage({
       allowRepeating: true,
       source: MESSAGE_SOURCE.CONSOLE_API,
       type: MESSAGE_TYPE.LOG,
--- a/devtools/client/webconsole/new-console-output/types.js
+++ b/devtools/client/webconsole/new-console-output/types.js
@@ -28,9 +28,10 @@ exports.ConsoleMessage = Immutable.Recor
   source: null,
   type: null,
   level: null,
   messageText: null,
   parameters: null,
   repeat: 1,
   repeatId: null,
   stacktrace: null,
+  frame: null,
 });
--- a/devtools/client/webconsole/new-console-output/utils/messages.js
+++ b/devtools/client/webconsole/new-console-output/utils/messages.js
@@ -57,23 +57,30 @@ function transformPacket(packet) {
           type = MESSAGE_TYPE.LOG;
           let {counter} = message;
           let label = counter.label ? counter.label : l10n.getStr("noCounterLabel");
           messageText = `${label}: ${counter.count}`;
           parameters = null;
           break;
       }
 
+      const frame = {
+        source: message.filename || null,
+        line: message.lineNumber || null,
+        column: message.columnNumber || null
+      };
+
       return new ConsoleMessage({
         source: MESSAGE_SOURCE.CONSOLE_API,
         type,
         level,
         parameters,
         messageText,
         stacktrace: message.stacktrace,
+        frame
       });
     }
 
     case "pageError": {
       let { pageError } = packet;
       let level = MESSAGE_LEVEL.ERROR;
       if (pageError.warning || pageError.strict) {
         level = MESSAGE_LEVEL.WARN;