Bug 1363680 - Move the repeat information outside of the message type. r=Honza draft
authorNicolas Chevobbe <nchevobbe@mozilla.com>
Mon, 05 Jun 2017 14:15:09 +0200
changeset 589001 2d216915e9e3c59b9d128f4484b340d902bc9c86
parent 588783 8a3aa1701537ea6b8334f432cd030d260d492fa3
child 589002 ccd6b6c4b096975e22f3d9193f43504a97733ed8
push id62217
push userbmo:nchevobbe@mozilla.com
push dateMon, 05 Jun 2017 12:19:44 +0000
reviewersHonza
bugs1363680
milestone55.0a1
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 = {};