Bug 1530133 Part 2 - Allow clearing console messages by their logpoint ID, r=nchevobbe.
authorBrian Hackett <bhackett1024@gmail.com>
Sat, 23 Feb 2019 16:19:17 -1000
changeset 520398 1e997aba85bb7f086ca9a41d3df8a020dee57118
parent 520397 b0310f8849e0806a47e5c45f41be37dd4c1cc39e
child 520399 0385531495c51233881ec821e3248a5a90c617f1
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnchevobbe
bugs1530133
milestone67.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 1530133 Part 2 - Allow clearing console messages by their logpoint ID, r=nchevobbe.
devtools/client/webconsole/actions/messages.js
devtools/client/webconsole/constants.js
devtools/client/webconsole/enhancers/actor-releaser.js
devtools/client/webconsole/reducers/messages.js
devtools/client/webconsole/utils/messages.js
devtools/client/webconsole/webconsole-connection-proxy.js
devtools/client/webconsole/webconsole-wrapper.js
--- a/devtools/client/webconsole/actions/messages.js
+++ b/devtools/client/webconsole/actions/messages.js
@@ -12,16 +12,17 @@ const {
 const { IdGenerator } = require("devtools/client/webconsole/utils/id-generator");
 const { batchActions } = require("devtools/client/shared/redux/middleware/debounce");
 
 const {
   MESSAGES_ADD,
   NETWORK_MESSAGE_UPDATE,
   NETWORK_UPDATE_REQUEST,
   MESSAGES_CLEAR,
+  MESSAGES_CLEAR_LOGPOINT,
   MESSAGE_OPEN,
   MESSAGE_CLOSE,
   MESSAGE_TYPE,
   MESSAGE_TABLE_RECEIVE,
   PAUSED_EXCECUTION_POINT,
   PRIVATE_MESSAGES_CLEAR,
 } = require("../constants");
 
@@ -53,16 +54,23 @@ function messagesAdd(packets, idGenerato
 }
 
 function messagesClear() {
   return {
     type: MESSAGES_CLEAR,
   };
 }
 
+function messagesClearLogpoint(logpointId) {
+  return {
+    type: MESSAGES_CLEAR_LOGPOINT,
+    logpointId,
+  };
+}
+
 function setPauseExecutionPoint(executionPoint) {
   return {
     type: PAUSED_EXCECUTION_POINT,
     executionPoint,
   };
 }
 
 function privateMessagesClear() {
@@ -135,16 +143,17 @@ function networkUpdateRequest(id, data) 
     id,
     data,
   };
 }
 
 module.exports = {
   messagesAdd,
   messagesClear,
+  messagesClearLogpoint,
   messageOpen,
   messageClose,
   messageTableDataGet,
   networkMessageUpdate,
   networkUpdateRequest,
   privateMessagesClear,
   // for test purpose only.
   messageTableDataReceive,
--- a/devtools/client/webconsole/constants.js
+++ b/devtools/client/webconsole/constants.js
@@ -20,16 +20,17 @@ const actionTypes = {
   FILTERS_CLEAR: "FILTERS_CLEAR",
   HISTORY_LOADED: "HISTORY_LOADED",
   INITIALIZE: "INITIALIZE",
   MESSAGE_CLOSE: "MESSAGE_CLOSE",
   MESSAGE_OPEN: "MESSAGE_OPEN",
   MESSAGE_TABLE_RECEIVE: "MESSAGE_TABLE_RECEIVE",
   MESSAGES_ADD: "MESSAGES_ADD",
   MESSAGES_CLEAR: "MESSAGES_CLEAR",
+  MESSAGES_CLEAR_LOGPOINT: "MESSAGES_CLEAR_LOGPOINT",
   NETWORK_MESSAGE_UPDATE: "NETWORK_MESSAGE_UPDATE",
   NETWORK_UPDATE_REQUEST: "NETWORK_UPDATE_REQUEST",
   PERSIST_TOGGLE: "PERSIST_TOGGLE",
   PRIVATE_MESSAGES_CLEAR: "PRIVATE_MESSAGES_CLEAR",
   REMOVE_NOTIFICATION: "REMOVE_NOTIFICATION",
   REMOVED_ACTORS_CLEAR: "REMOVED_ACTORS_CLEAR",
   REVERSE_SEARCH_INPUT_TOGGLE: "REVERSE_SEARCH_INPUT_TOGGLE",
   SELECT_NETWORK_MESSAGE_TAB: "SELECT_NETWORK_MESSAGE_TAB",
--- a/devtools/client/webconsole/enhancers/actor-releaser.js
+++ b/devtools/client/webconsole/enhancers/actor-releaser.js
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {
   MESSAGES_ADD,
   MESSAGES_CLEAR,
   PRIVATE_MESSAGES_CLEAR,
+  MESSAGES_CLEAR_LOGPOINT,
   REMOVED_ACTORS_CLEAR,
 } = require("devtools/client/webconsole/constants");
 
 /**
  * This enhancer is responsible for releasing actors on the backend.
  * When messages with arguments are removed from the store we should also
  * clean up the backend.
  */
@@ -20,17 +21,18 @@ function enableActorReleaser(webConsoleU
   return next => (reducer, initialState, enhancer) => {
     function releaseActorsEnhancer(state, action) {
       state = reducer(state, action);
 
       const type = action.type;
       const proxy = webConsoleUI ? webConsoleUI.proxy : null;
       if (
         proxy &&
-        ([MESSAGES_ADD, MESSAGES_CLEAR, PRIVATE_MESSAGES_CLEAR].includes(type))
+          ([MESSAGES_ADD, MESSAGES_CLEAR, PRIVATE_MESSAGES_CLEAR,
+            MESSAGES_CLEAR_LOGPOINT].includes(type))
       ) {
         releaseActors(state.messages.removedActors, proxy);
 
         // Reset `removedActors` in message reducer.
         state = reducer(state, {
           type: REMOVED_ACTORS_CLEAR,
         });
       }
--- a/devtools/client/webconsole/reducers/messages.js
+++ b/devtools/client/webconsole/reducers/messages.js
@@ -53,32 +53,35 @@ const MessageState = overrides => Object
   // in order to properly release them.
   // This array is not supposed to be consumed by any UI component.
   removedActors: [],
   // Map of the form {messageId : numberOfRepeat}
   repeatById: {},
   // Map of the form {messageId : networkInformation}
   // `networkInformation` holds request, response, totalTime, ...
   networkMessagesUpdateById: {},
+  // Set of logpoint IDs that have been removed
+  removedLogpointIds: new Set(),
   pausedExecutionPoint: null,
 }, overrides));
 
 function cloneState(state) {
   return {
     messagesById: new Map(state.messagesById),
     replayProgressMessages: new Set(state.replayProgressMessages),
     visibleMessages: [...state.visibleMessages],
     filteredMessagesCount: {...state.filteredMessagesCount},
     messagesUiById: [...state.messagesUiById],
     messagesTableDataById: new Map(state.messagesTableDataById),
     groupsById: new Map(state.groupsById),
     currentGroup: state.currentGroup,
     removedActors: [...state.removedActors],
     repeatById: {...state.repeatById},
     networkMessagesUpdateById: {...state.networkMessagesUpdateById},
+    removedLogpointIds: new Set(state.removedLogpointIds),
     pausedExecutionPoint: state.pausedExecutionPoint,
   };
 }
 
 function addMessage(state, filtersState, prefsState, newMessage) {
   const {
     messagesById,
     replayProgressMessages,
@@ -87,26 +90,35 @@ function addMessage(state, filtersState,
     repeatById,
   } = state;
 
   if (newMessage.type === constants.MESSAGE_TYPE.NULL_MESSAGE) {
     // When the message has a NULL type, we don't add it.
     return state;
   }
 
-  if (newMessage.executionPoint) {
+  if (newMessage.executionPoint && !newMessage.logpointId) {
     // When replaying old behaviors in a tab, we might see the same messages
     // multiple times. Ignore duplicate messages with the same progress values.
+    // We don't need to do this for logpoint messages, which will only arrive once.
     const progress = newMessage.executionPoint.progress;
     if (replayProgressMessages.has(progress)) {
       return state;
     }
     state.replayProgressMessages.add(progress);
   }
 
+  // After messages with a given logpoint ID have been removed, ignore all
+  // future messages with that ID.
+  if (newMessage.logpointId &&
+      state.removedLogpointIds &&
+      state.removedLogpointIds.has(newMessage.logpointId)) {
+    return state;
+  }
+
   if (newMessage.type === constants.MESSAGE_TYPE.END_GROUP) {
     // Compute the new current group.
     state.currentGroup = getNewCurrentGroup(currentGroup, groupsById);
     return state;
   }
 
   if (newMessage.allowRepeating && messagesById.size > 0) {
     const lastMessage = [...messagesById.values()][messagesById.size - 1];
@@ -220,32 +232,51 @@ function messages(state = MessageState()
         // Store all actors from removed messages. This array is used by
         // `releaseActorsEnhancer` to release all of those backend actors.
         removedActors: [...state.messagesById.values()].reduce((res, msg) => {
           res.push(...getAllActorsInMessage(msg));
           return res;
         }, []),
       });
 
-    case constants.PRIVATE_MESSAGES_CLEAR:
+    case constants.PRIVATE_MESSAGES_CLEAR: {
       const removedIds = [];
       for (const [id, message] of messagesById) {
         if (message.private === true) {
           removedIds.push(id);
         }
       }
 
       // If there's no private messages, there's no need to change the state.
       if (removedIds.length === 0) {
         return state;
       }
 
       return removeMessagesFromState({
         ...state,
       }, removedIds);
+    }
+
+    case constants.MESSAGES_CLEAR_LOGPOINT: {
+      const removedIds = [];
+      for (const [id, message] of messagesById) {
+        if (message.logpointId == action.logpointId) {
+          removedIds.push(id);
+        }
+      }
+
+      if (removedIds.length === 0) {
+        return state;
+      }
+
+      return removeMessagesFromState({
+        ...state,
+        removedLogpointIds: new Set([...state.removedLogpointIds, action.logpointId]),
+      }, removedIds);
+    }
 
     case constants.MESSAGE_OPEN:
       const openState = {...state};
       openState.messagesUiById = [...messagesUiById, action.id];
       const currMessage = messagesById.get(action.id);
 
       // If the message is a group
       if (isGroupType(currMessage.type)) {
--- a/devtools/client/webconsole/utils/messages.js
+++ b/devtools/client/webconsole/utils/messages.js
@@ -189,16 +189,17 @@ function transformConsoleAPICallPacket(p
     messageText,
     stacktrace: message.stacktrace ? message.stacktrace : null,
     frame,
     timeStamp: message.timeStamp,
     userProvidedStyles: message.styles,
     prefix: message.prefix,
     private: message.private,
     executionPoint: message.executionPoint,
+    logpointId: message.logpointId,
   });
 }
 
 function transformNavigationMessagePacket(packet) {
   const { url } = packet;
   return new ConsoleMessage({
     source: MESSAGE_SOURCE.CONSOLE_API,
     type: MESSAGE_TYPE.NAVIGATION_MARKER,
--- a/devtools/client/webconsole/webconsole-connection-proxy.js
+++ b/devtools/client/webconsole/webconsole-connection-proxy.js
@@ -34,16 +34,17 @@ function WebConsoleConnectionProxy(webCo
   this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
   this._onTabNavigated = this._onTabNavigated.bind(this);
   this._onTabWillNavigate = this._onTabWillNavigate.bind(this);
   this._onAttachConsole = this._onAttachConsole.bind(this);
   this._onCachedMessages = this._onCachedMessages.bind(this);
   this._connectionTimeout = this._connectionTimeout.bind(this);
   this._onLastPrivateContextExited =
     this._onLastPrivateContextExited.bind(this);
+  this._clearLogpointMessages = this._clearLogpointMessages.bind(this);
 }
 
 WebConsoleConnectionProxy.prototype = {
   /**
    * The owning WebConsoleUI instance.
    *
    * @see WebConsoleUI
    * @type object
@@ -188,16 +189,17 @@ WebConsoleConnectionProxy.prototype = {
 
     this.webConsoleClient.on("networkEvent", this._onNetworkEvent);
     this.webConsoleClient.on("networkEventUpdate", this._onNetworkEventUpdate);
     this.webConsoleClient.on("logMessage", this._onLogMessage);
     this.webConsoleClient.on("pageError", this._onPageError);
     this.webConsoleClient.on("consoleAPICall", this._onConsoleAPICall);
     this.webConsoleClient.on("lastPrivateContextExited",
                              this._onLastPrivateContextExited);
+    this.webConsoleClient.on("clearLogpointMessages", this._clearLogpointMessages);
 
     const msgs = ["PageError", "ConsoleAPI"];
     const cachedMessages = await this.webConsoleClient.getCachedMessages(msgs);
     this._onCachedMessages(cachedMessages);
   },
 
   /**
    * Dispatch a message add on the new frontend and emit an event for tests.
@@ -301,16 +303,22 @@ WebConsoleConnectionProxy.prototype = {
   _onConsoleAPICall: function(packet) {
     if (!this.webConsoleUI) {
       return;
     }
     packet.type = "consoleAPICall";
     this.dispatchMessageAdd(packet);
   },
 
+  _clearLogpointMessages(logpointId) {
+    if (this.webConsoleUI) {
+      this.webConsoleUI.wrapper.dispatchClearLogpointMessages(logpointId);
+    }
+  },
+
   /**
    * The "networkEvent" message type handler. We redirect any message to
    * the UI for displaying.
    *
    * @private
    * @param object networkInfo
    *        The network request information.
    */
@@ -416,16 +424,17 @@ WebConsoleConnectionProxy.prototype = {
 
     this.webConsoleClient.off("logMessage", this._onLogMessage);
     this.webConsoleClient.off("pageError", this._onPageError);
     this.webConsoleClient.off("consoleAPICall", this._onConsoleAPICall);
     this.webConsoleClient.off("lastPrivateContextExited",
                                this._onLastPrivateContextExited);
     this.webConsoleClient.off("networkEvent", this._onNetworkEvent);
     this.webConsoleClient.off("networkEventUpdate", this._onNetworkEventUpdate);
+    this.webConsoleClient.off("clearLogpointMessages", this._clearLogpointMessages);
     this.target.off("will-navigate", this._onTabWillNavigate);
     this.target.off("navigate", this._onTabNavigated);
 
     this.client = null;
     this.webConsoleClient = null;
     this.target = null;
     this.connected = false;
     this.webConsoleUI = null;
--- a/devtools/client/webconsole/webconsole-wrapper.js
+++ b/devtools/client/webconsole/webconsole-wrapper.js
@@ -543,16 +543,20 @@ class WebConsoleWrapper {
     this.setTimeoutIfNeeded();
   }
 
   batchedMessagesAdd(messages) {
     this.queuedMessageAdds = this.queuedMessageAdds.concat(messages);
     this.setTimeoutIfNeeded();
   }
 
+  dispatchClearLogpointMessages(logpointId) {
+    store.dispatch(actions.messagesClearLogpoint(logpointId));
+  }
+
   dispatchClearHistory() {
     store.dispatch(actions.clearHistory());
   }
 
   /**
    * Returns a Promise that resolves once any async dispatch is finally dispatched.
    */
   waitAsyncDispatches() {