Bug 1363680 - Move the repeat information outside of the message type. r=Honza
authorNicolas Chevobbe <nchevobbe@mozilla.com>
Mon, 05 Jun 2017 14:15:09 +0200
changeset 412852 6daa1d690d1a04aaca7220cf401945f9bee5acd3
parent 412851 6ebd3de09d6c2be8ffc4ce977845068f0464e96f
child 412853 60f2048eab815fa14e0d46f21bab66608a98ab70
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersHonza
bugs1363680
milestone55.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 1363680 - Move the repeat information outside of the message type. r=Honza MozReview-Commit-ID: J7IJgEYnLhn
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/reducers/messages.js
devtools/client/webconsole/new-console-output/selectors/messages.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
@@ -10,16 +10,17 @@ const {
   PropTypes
 } = require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 
 const {
   getAllMessagesUiById,
   getAllMessagesTableDataById,
   getVisibleMessages,
+  getAllRepeatById,
 } = 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({
 
   displayName: "ConsoleOutput",
 
   propTypes: {
@@ -27,16 +28,17 @@ const ConsoleOutput = createClass({
     serviceContainer: PropTypes.shape({
       attachRefToHud: PropTypes.func.isRequired,
       openContextMenu: PropTypes.func.isRequired,
       sourceMapService: PropTypes.object,
     }),
     dispatch: PropTypes.func.isRequired,
     timestampsVisible: PropTypes.bool,
     messagesTableData: PropTypes.object.isRequired,
+    messagesRepeat: PropTypes.object.isRequired,
     visibleMessages: PropTypes.array.isRequired,
   },
 
   componentDidMount() {
     // Do the scrolling in the nextTick since this could hit console startup performances.
     // See https://bugzilla.mozilla.org/show_bug.cgi?id=1355869
     setTimeout(() => {
       scrollToBottom(this.outputNode);
@@ -70,31 +72,33 @@ const ConsoleOutput = createClass({
   },
 
   render() {
     let {
       dispatch,
       visibleMessages,
       messagesUi,
       messagesTableData,
+      messagesRepeat,
       serviceContainer,
       timestampsVisible,
     } = this.props;
 
     let messageNodes = visibleMessages.map((message) => {
       return (
         MessageContainer({
           dispatch,
           message,
           key: message.id,
           serviceContainer,
           open: messagesUi.includes(message.id),
           tableData: messagesTableData.get(message.id),
           indent: message.indent,
           timestampsVisible,
+          repeat: messagesRepeat[message.id]
         })
       );
     });
 
     return (
       dom.div({
         className: "webconsole-output",
         onContextMenu: this.onContextMenu,
@@ -118,13 +122,14 @@ function isScrolledToBottom(outputNode, 
          scrollNode.scrollHeight - lastNodeHeight / 2;
 }
 
 function mapStateToProps(state, props) {
   return {
     visibleMessages: getVisibleMessages(state),
     messagesUi: getAllMessagesUiById(state),
     messagesTableData: getAllMessagesTableDataById(state),
+    messagesRepeat: getAllRepeatById(state),
     timestampsVisible: state.ui.timestampsVisible,
   };
 }
 
 module.exports = connect(mapStateToProps)(ConsoleOutput);
--- a/devtools/client/webconsole/new-console-output/components/message-container.js
+++ b/devtools/client/webconsole/new-console-output/components/message-container.js
@@ -32,27 +32,28 @@ const MessageContainer = createClass({
 
   propTypes: {
     message: PropTypes.object.isRequired,
     open: PropTypes.bool.isRequired,
     serviceContainer: PropTypes.object.isRequired,
     indent: PropTypes.number.isRequired,
     tableData: PropTypes.object,
     timestampsVisible: PropTypes.bool.isRequired,
+    repeat: PropTypes.object,
   },
 
   getDefaultProps: function () {
     return {
       open: false,
       indent: 0,
     };
   },
 
   shouldComponentUpdate(nextProps, nextState) {
-    const repeatChanged = this.props.message.repeat !== nextProps.message.repeat;
+    const repeatChanged = this.props.repeat !== nextProps.repeat;
     const openChanged = this.props.open !== nextProps.open;
     const tableDataChanged = this.props.tableData !== nextProps.tableData;
     const responseChanged = this.props.message.response !== nextProps.message.response;
     const totalTimeChanged = this.props.message.totalTime !== nextProps.message.totalTime;
     const timestampVisibleChanged =
       this.props.timestampsVisible !== nextProps.timestampsVisible;
 
     return repeatChanged
--- 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
@@ -37,23 +37,23 @@ function ConsoleApiCall(props) {
   const {
     dispatch,
     message,
     open,
     tableData,
     serviceContainer,
     indent,
     timestampsVisible,
+    repeat,
   } = props;
   const {
     id: messageId,
     source,
     type,
     level,
-    repeat,
     stacktrace,
     frame,
     timeStamp,
     parameters,
     messageText,
     userProvidedStyles,
   } = message;
 
--- a/devtools/client/webconsole/new-console-output/reducers/messages.js
+++ b/devtools/client/webconsole/new-console-output/reducers/messages.js
@@ -30,25 +30,28 @@ const MessageState = Immutable.Record({
   // Map of the form {groupMessageId : groupArray},
   // where groupArray is the list of of all the parent groups' ids of the groupMessageId.
   groupsById: Immutable.Map(),
   // Message id of the current group (no corresponding console.groupEnd yet).
   currentGroup: null,
   // List of removed messages is used to release related (parameters) actors.
   // This array is not supposed to be consumed by any UI component.
   removedMessages: [],
+  // Map of the form {messageId : numberOfRepeat}
+  repeatById: {}
 });
 
 function messages(state = new MessageState(), action, filtersState, prefsState) {
   const {
     messagesById,
     messagesUiById,
     messagesTableDataById,
     groupsById,
     currentGroup,
+    repeatById,
     visibleMessages,
   } = state;
 
   const {logLimit} = prefsState;
 
   switch (action.type) {
     case constants.MESSAGE_ADD:
       let newMessage = action.message;
@@ -60,23 +63,25 @@ function messages(state = new MessageSta
 
       if (newMessage.type === constants.MESSAGE_TYPE.END_GROUP) {
         // Compute the new current group.
         return state.set("currentGroup", getNewCurrentGroup(currentGroup, groupsById));
       }
 
       if (newMessage.allowRepeating && messagesById.size > 0) {
         let lastMessage = messagesById.last();
-        if (lastMessage.repeatId === newMessage.repeatId) {
+        if (
+          lastMessage.repeatId === newMessage.repeatId
+          && lastMessage.groupId === currentGroup
+        ) {
           return state.set(
-            "messagesById",
-            messagesById.set(
-              lastMessage.id,
-              lastMessage.set("repeat", lastMessage.repeat + 1)
-            )
+            "repeatById",
+            Object.assign({}, repeatById, {
+              [lastMessage.id]: (repeatById[lastMessage.id] || 1) + 1
+            })
           );
         }
       }
 
       return state.withMutations(function (record) {
         // Add the new message with a reference to the parent group.
         let parentGroups = getParentGroups(currentGroup, groupsById);
         const addedMessage = newMessage.withMutations(function (message) {
@@ -316,16 +321,27 @@ function limitTopLevelMessageCount(state
   if (mapHasRemovedIdKey(record.messagesTableDataById)) {
     record.set("messagesTableDataById",
       record.messagesTableDataById.withMutations(cleanUpCollection));
   }
   if (mapHasRemovedIdKey(record.groupsById)) {
     record.set("groupsById", record.groupsById.withMutations(cleanUpCollection));
   }
 
+  if (Object.keys(record.repeatById).includes(removedMessagesId)) {
+    record.set("repeatById",
+      [...Object.entries(record.repeatById)].reduce((res, [id, repeat]) => {
+        if (!isInRemovedId(id)) {
+          res[id] = repeat;
+        }
+        return res;
+      }, {})
+    );
+  }
+
   return record;
 }
 
 /**
  * Returns total count of top level messages (those which are not
  * within a group).
  */
 function getToplevelMessageCount(record) {
--- a/devtools/client/webconsole/new-console-output/selectors/messages.js
+++ b/devtools/client/webconsole/new-console-output/selectors/messages.js
@@ -28,17 +28,22 @@ function getAllGroupsById(state) {
 function getCurrentGroup(state) {
   return state.messages.currentGroup;
 }
 
 function getVisibleMessages(state) {
   return state.messages.visibleMessages.map(id => getMessage(state, id));
 }
 
+function getAllRepeatById(state) {
+  return state.messages.repeatById;
+}
+
 module.exports = {
   getMessage,
   getAllMessagesById,
   getAllMessagesUiById,
   getAllMessagesTableDataById,
   getAllGroupsById,
   getCurrentGroup,
   getVisibleMessages,
+  getAllRepeatById,
 };
--- a/devtools/client/webconsole/new-console-output/types.js
+++ b/devtools/client/webconsole/new-console-output/types.js
@@ -28,17 +28,16 @@ exports.ConsoleMessage = Immutable.Recor
   id: null,
   allowRepeating: true,
   source: null,
   timeStamp: null,
   type: null,
   level: null,
   messageText: null,
   parameters: null,
-  repeat: 1,
   repeatId: null,
   stacktrace: null,
   frame: null,
   groupId: null,
   exceptionDocURL: null,
   userProvidedStyles: null,
   notes: null,
   indent: 0,
--- a/devtools/client/webconsole/new-console-output/utils/messages.js
+++ b/devtools/client/webconsole/new-console-output/utils/messages.js
@@ -232,17 +232,16 @@ function transformPacket(packet) {
       });
     }
   }
 }
 
 // Helpers
 function getRepeatId(message) {
   message = message.toJS();
-  message.repeat = null;
   message.timeStamp = null;
   return JSON.stringify(message);
 }
 
 function convertCachedPacket(packet) {
   // The devtools server provides cached message packets in a different shape, so we
   // transform them here.
   let convertPacket = {};