Bug 1495300 - Add paused and jump badge to console api messages r=jlast
authorAnshul Malik <malikanshul29@gmail.com>
Tue, 02 Oct 2018 18:32:55 +0000
changeset 494947 8b650bb26b719660566eef5493a920a481027b12
parent 494946 6eec41ce0c9469c33e4d1cbd9b412ce1d70d93c7
child 494948 f69ecb2abf86e239c528a27f394e88019bd7cdae
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlast
bugs1495300
milestone64.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
Bug 1495300 - Add paused and jump badge to console api messages r=jlast Differential Revision: https://phabricator.services.mozilla.com/D7327
devtools/client/jar.mn
devtools/client/themes/images/webconsole/jump.svg
devtools/client/themes/variables.css
devtools/client/themes/webconsole.css
devtools/client/webconsole/components/ConsoleOutput.js
devtools/client/webconsole/components/Message.js
devtools/client/webconsole/components/MessageContainer.js
devtools/client/webconsole/components/MessageIcon.js
devtools/client/webconsole/components/message-types/ConsoleApiCall.js
devtools/client/webconsole/webconsole-output-wrapper.js
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -152,16 +152,17 @@ devtools.jar:
     skin/markup.css (themes/markup.css)
     skin/images/editor-error.png (themes/images/editor-error.png)
     skin/images/breakpoint.svg (themes/images/breakpoint.svg)
     skin/webconsole.css (themes/webconsole.css)
     skin/images/webconsole/alert.svg (themes/images/webconsole/alert.svg)
     skin/images/webconsole/info.svg (themes/images/webconsole/info.svg)
     skin/images/webconsole/input.svg (themes/images/webconsole/input.svg)
     skin/images/webconsole/return.svg (themes/images/webconsole/return.svg)
+    skin/images/webconsole/jump.svg (themes/images/webconsole/jump.svg)
     skin/images/breadcrumbs-scrollbutton.svg (themes/images/breadcrumbs-scrollbutton.svg)
     skin/animation.css (themes/animation.css)
     skin/canvasdebugger.css (themes/canvasdebugger.css)
     skin/debugger.css (themes/debugger.css)
     skin/perf.css (themes/perf.css)
     skin/performance.css (themes/performance.css)
     skin/memory.css (themes/memory.css)
     skin/scratchpad.css (themes/scratchpad.css)
new file mode 100755
--- /dev/null
+++ b/devtools/client/themes/images/webconsole/jump.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 51.3 (57544) - http://www.bohemiancoding.com/sketch -->
+    <title>Group 7</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Group-7" transform="translate(1.000000, 1.000000)">
+            <g id="Group-6">
+                <circle id="Oval-2" stroke="#0274E8" cx="8" cy="8" r="8"></circle>
+                <polygon id="Triangle" fill="#0274E8" transform="translate(9.000000, 8.000000) rotate(90.000000) translate(-9.000000, -8.000000) " points="9 5 13 11 5 11"></polygon>
+            </g>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
--- a/devtools/client/themes/variables.css
+++ b/devtools/client/themes/variables.css
@@ -212,16 +212,17 @@
   /* Images */
   --select-arrow-image: url(chrome://devtools/skin/images/select-arrow.svg);
   --theme-pane-collapse-image: url(chrome://devtools/skin/images/pane-collapse.svg);
   --theme-pane-expand-image: url(chrome://devtools/skin/images/pane-expand.svg);
   --theme-console-alert-image: url(chrome://devtools/skin/images/webconsole/alert.svg);
   --theme-console-info-image: url(chrome://devtools/skin/images/webconsole/info.svg);
   --theme-console-input-image: url(chrome://devtools/skin/images/webconsole/input.svg);
   --theme-console-return-image: url(chrome://devtools/skin/images/webconsole/return.svg);
+  --theme-console-jump-image: url(chrome://devtools/skin/images/webconsole/jump.svg);
 
   /* Firefox Colors CSS Variables v1.0.3
    * Colors are taken from: https://github.com/FirefoxUX/design-tokens
    * Some intermediate colors were added (names ending in '5').
    */
   --magenta-50: #ff1ad9;
   --magenta-65: #dd00a9;
   --magenta-70: #b5007f;
--- a/devtools/client/themes/webconsole.css
+++ b/devtools/client/themes/webconsole.css
@@ -184,16 +184,28 @@ a {
   background-image: var(--theme-console-alert-image);
 }
 
 .message.warn > .icon {
   color: var(--console-output-icon-warning);
   background-image: var(--theme-console-alert-image);
 }
 
+
+span.icon[title="Jump"] {
+  background-image:var(--theme-console-jump-image);
+  background-size: 14px 14px;
+  cursor: pointer;
+  opacity: 0;
+}
+
+.message:hover span.icon[title="Jump"] {
+  opacity: 1;
+}
+
 .message > .message-body-wrapper {
   flex: auto;
   min-width: 0px;
   margin: var(--console-output-vertical-padding) 0;
 }
 
 .message-body-wrapper .table-widget-body {
   overflow: visible;
--- a/devtools/client/webconsole/components/ConsoleOutput.js
+++ b/devtools/client/webconsole/components/ConsoleOutput.js
@@ -148,17 +148,17 @@ class ConsoleOutput extends Component {
       messageId,
       serviceContainer,
       open: messagesUi.includes(messageId),
       tableData: messagesTableData.get(messageId),
       timestampsVisible,
       repeat: messagesRepeat[messageId],
       networkMessageUpdate: networkMessagesUpdate[messageId],
       networkMessageActiveTabId,
-      getMessage: () => messages.get(messageId),
+      getMessage: () => messages.get(messageId)
     }));
 
     return (
       dom.div({
         className: "webconsole-output",
         onContextMenu: this.onContextMenu,
         ref: node => {
           this.outputNode = node;
--- a/devtools/client/webconsole/components/Message.js
+++ b/devtools/client/webconsole/components/Message.js
@@ -39,16 +39,17 @@ class Message extends Component {
       indent: PropTypes.number.isRequired,
       topLevelClasses: PropTypes.array.isRequired,
       messageBody: PropTypes.any.isRequired,
       repeat: PropTypes.any,
       frame: PropTypes.any,
       attachment: PropTypes.any,
       stacktrace: PropTypes.any,
       messageId: PropTypes.string,
+      executionPoint: PropTypes.string,
       scrollToMessage: PropTypes.bool,
       exceptionDocURL: PropTypes.string,
       request: PropTypes.object,
       dispatch: PropTypes.func,
       timeStamp: PropTypes.number,
       timestampsVisible: PropTypes.bool.isRequired,
       serviceContainer: PropTypes.shape({
         emitNewMessage: PropTypes.func.isRequired,
@@ -57,31 +58,32 @@ class Message extends Component {
         onViewSourceInStyleEditor: PropTypes.func,
         openContextMenu: PropTypes.func.isRequired,
         openLink: PropTypes.func.isRequired,
         sourceMapService: PropTypes.any,
       }),
       notes: PropTypes.arrayOf(PropTypes.shape({
         messageBody: PropTypes.string.isRequired,
         frame: PropTypes.any,
-      })),
+      }))
     };
   }
 
   static get defaultProps() {
     return {
       indent: 0
     };
   }
 
   constructor(props) {
     super(props);
     this.onLearnMoreClick = this.onLearnMoreClick.bind(this);
     this.toggleMessage = this.toggleMessage.bind(this);
     this.onContextMenu = this.onContextMenu.bind(this);
+    this.renderIcon = this.renderIcon.bind(this);
   }
 
   componentDidMount() {
     if (this.messageNode) {
       if (this.props.scrollToMessage) {
         this.messageNode.scrollIntoView();
       }
       // Event used in tests. Some message types don't pass it in because existing tests
@@ -114,16 +116,31 @@ class Message extends Component {
       request,
       messageId,
     };
     serviceContainer.openContextMenu(e, messageInfo);
     e.stopPropagation();
     e.preventDefault();
   }
 
+  renderIcon() {
+    const { level, messageId, executionPoint, serviceContainer } = this.props;
+
+    if (serviceContainer.canRewind()) {
+      return dom.span({
+        className: "icon",
+        title: "Jump",
+        "aria-live": "off",
+        onClick: () => serviceContainer.jumpToExecutionPoint(executionPoint, messageId)
+      });
+    }
+
+    return MessageIcon({ level });
+  }
+
   render() {
     const {
       open,
       collapsible,
       collapseTitle,
       source,
       type,
       level,
@@ -131,32 +148,32 @@ class Message extends Component {
       topLevelClasses,
       messageBody,
       frame,
       stacktrace,
       serviceContainer,
       exceptionDocURL,
       timeStamp = Date.now(),
       timestampsVisible,
-      notes,
+      notes
     } = this.props;
 
     topLevelClasses.push("message", source, type, level);
     if (open) {
       topLevelClasses.push("open");
     }
 
     let timestampEl;
     if (timestampsVisible === true) {
       timestampEl = dom.span({
         className: "timestamp devtools-monospace"
       }, l10n.timestampString(timeStamp));
     }
 
-    const icon = MessageIcon({level});
+    const icon = this.renderIcon();
 
     // Figure out if there is an expandable part to the message.
     let attachment = null;
     if (this.props.attachment) {
       attachment = this.props.attachment;
     } else if (stacktrace && open) {
       attachment = dom.div(
         {
--- a/devtools/client/webconsole/components/MessageContainer.js
+++ b/devtools/client/webconsole/components/MessageContainer.js
@@ -29,17 +29,17 @@ class MessageContainer extends Component
     return {
       messageId: PropTypes.string.isRequired,
       open: PropTypes.bool.isRequired,
       serviceContainer: PropTypes.object.isRequired,
       tableData: PropTypes.object,
       timestampsVisible: PropTypes.bool.isRequired,
       repeat: PropTypes.number,
       networkMessageUpdate: PropTypes.object,
-      getMessage: PropTypes.func.isRequired,
+      getMessage: PropTypes.func.isRequired
     };
   }
 
   static get defaultProps() {
     return {
       open: false,
     };
   }
--- a/devtools/client/webconsole/components/MessageIcon.js
+++ b/devtools/client/webconsole/components/MessageIcon.js
@@ -12,17 +12,17 @@ const {l10n} = require("devtools/client/
 
 // Store common icons so they can be used without recreating the element
 // during render.
 const CONSTANT_ICONS = {
   "error": getIconElement("level.error"),
   "warn": getIconElement("level.warn"),
   "info": getIconElement("level.info"),
   "log": getIconElement("level.log"),
-  "debug": getIconElement("level.debug"),
+  "debug": getIconElement("level.debug")
 };
 
 function getIconElement(level) {
   return dom.span({
     className: "icon",
     title: l10n.getStr(level),
     "aria-live": "off",
   });
--- a/devtools/client/webconsole/components/message-types/ConsoleApiCall.js
+++ b/devtools/client/webconsole/components/message-types/ConsoleApiCall.js
@@ -37,16 +37,17 @@ function ConsoleApiCall(props) {
     open,
     tableData,
     serviceContainer,
     timestampsVisible,
     repeat,
   } = props;
   const {
     id: messageId,
+    executionPoint,
     indent,
     source,
     type,
     level,
     stacktrace,
     frame,
     timeStamp,
     parameters,
@@ -108,16 +109,17 @@ function ConsoleApiCall(props) {
   }
 
   const collapsible = isGroupType(type)
     || (type === "error" && Array.isArray(stacktrace));
   const topLevelClasses = ["cm-s-mozilla"];
 
   return Message({
     messageId,
+    executionPoint,
     open,
     collapsible,
     collapseTitle,
     source,
     type,
     level,
     topLevelClasses,
     messageBody,
--- a/devtools/client/webconsole/webconsole-output-wrapper.js
+++ b/devtools/client/webconsole/webconsole-output-wrapper.js
@@ -60,16 +60,23 @@ WebConsoleOutputWrapper.prototype = {
             messageId,
             timeStamp,
           }]));
         },
         hudProxy: hud.proxy,
         openLink: (url, e) => {
           hud.owner.openLink(url, e);
         },
+        canRewind: () => {
+          if (!hud.owner.target.activeTab) {
+            return false;
+          }
+
+          return hud.owner.target.activeTab.traits.canRewind;
+        },
         createElement: nodename => {
           return this.document.createElement(nodename);
         },
         getLongString: (grip) => {
           return hud.proxy.webConsoleClient.getString(grip);
         },
         requestData(id, type) {
           return hud.proxy.networkDataProvider.requestData(id, type);
@@ -215,17 +222,19 @@ WebConsoleOutputWrapper.prototype = {
               inspector
             ] = await Promise.all([onGripNodeToFront, onSelectInspector]);
 
             const onInspectorUpdated = inspector.once("inspector-updated");
             const onNodeFrontSet = this.toolbox.selection
               .setNodeFront(front, { reason: "console" });
 
             return Promise.all([onNodeFrontSet, onInspectorUpdated]);
-          }
+          },
+          jumpToExecutionPoint: executionPoint =>
+            this.toolbox.threadClient.timeWarp(executionPoint)
         });
       }
 
       store = configureStore(this.hud, {
         // We may not have access to the toolbox (e.g. in the browser console).
         sessionId: this.toolbox && this.toolbox.sessionId || -1,
         telemetry: this.telemetry,
         services: serviceContainer